// import com.alibaba.druid.DbType;
// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.ast.expr.*;
// import com.alibaba.druid.sql.ast.expr.SQLCaseExpr.Item;
// import com.alibaba.druid.sql.ast.statement.*;
// import com.alibaba.druid.sql.ast.statement.SQLInsertStatement.ValuesClause;
// import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr;
// import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOutFileExpr;
// import com.alibaba.druid.sql.dialect.mysql.ast.statement.*;
// import com.alibaba.druid.sql.dialect.mysql.parser.MySqlStatementParser;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleExecuteImmediateStatement;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleLockTableStatement;
// import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleMultiInsertStatement;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerExecStatement;
// import com.alibaba.druid.sql.dialect.sqlserver.ast.stmt.SQLServerInsertStatement;
// import com.alibaba.druid.sql.parser.SQLStatementParser;
// import com.alibaba.druid.sql.visitor.ExportParameterVisitor;
// import com.alibaba.druid.sql.visitor.SQLEvalVisitor;
// import com.alibaba.druid.sql.visitor.SQLEvalVisitorUtils;
// import com.alibaba.druid.sql.visitor.functions.Nil;
// import com.alibaba.druid.support.logging.Log;
// import com.alibaba.druid.support.logging.LogFactory;
// import com.alibaba.druid.util.FnvHash;
// import com.alibaba.druid.util.JdbcUtils;
// import com.alibaba.druid.util.ServletPathMatcher;
// import com.alibaba.druid.util.StringUtils;
// import com.alibaba.druid.wall.*;
// import com.alibaba.druid.wall.WallConfig.TenantCallBack;
// import com.alibaba.druid.wall.WallConfig.TenantCallBack.StatementType;
// import com.alibaba.druid.wall.violation.ErrorCode;
// import com.alibaba.druid.wall.violation.IllegalSQLObjectViolation;

// import java.io.BufferedReader;
// import java.io.IOException;
// import java.io.InputStream;
// import java.io.InputStreamReader;
// import java.net.URL;
// import java.util.*;

// import static com.alibaba.druid.sql.visitor.SQLEvalVisitor.SQLEvalVisitor::EVAL_VALUE;
#include "WallVisitorUtils.h"
#include "../WallVisitor.h"
#include "../WallConfig.h"
#include "../violation/ErrorCode.h"
#include "../violation/IllegalSQLObjectViolation.h"
#include "../../sql/ast/statement/SQLSelect.h"
#include "../../sql/ast/statement/SQLSelectQuery.h"
#include "../../sql/ast/statement/SQLSelectQueryBlock.h"
#include "../../sql/ast/expr/SQLAggregateExpr.h"
#include "../../sql/ast/expr/SQLBinaryOpExpr.h"
#include "../../sql/ast/expr/SQLBinaryOpExprGroup.h"
#include "../../sql/ast/expr/SQLBooleanExpr.h"
#include "../../sql/ast/expr/SQLCharExpr.h"
#include "../../sql/ast/expr/SQLNCharExpr.h"
#include "../../sql/ast/expr/SQLNotExpr.h"
#include "../../sql/ast/expr/SQLQueryExpr.h"
#include "../../sql/ast/expr/SQLCaseExpr.h"
#include "../../sql/ast/expr/SQLMethodInvokeExpr.h"
#include "../../sql/ast/expr/SQLBetweenExpr.h"
#include "../../sql/ast/expr/SQLInListExpr.h"
#include "../../sql/ast/expr/SQLUnaryExpr.h"
#include "../../utils/instanceof.h"
#include "../../utils/FnvHash.h"
#include "../../sql/visitor/SQLEvalVisitor.h"
#include "../../sql/visitor/SQLEvalVisitorUtils.h"
#include "../../sql/visitor/functions/Nil.h"

//     static class WallVisitorUtils_WallTopStatementContext {
//         bool fromSysTable;
//         bool fromSysSchema;

//         bool fromPermitTable;

//         bool fromSysTable() {
//             return fromSysTable;
//         }

//         void setFromSysTable(bool fromSysTable) {
//             this->fromSysTable = fromSysTable;
//         }

//         bool fromSysSchema() {
//             return fromSysSchema;
//         }

//         void setFromSysSchema(bool fromSysSchema) {
//             this->fromSysSchema = fromSysSchema;
//         }

//         bool fromPermitTable() {
//             return fromPermitTable;
//         }

//         void setFromPermitTable(bool fromPermitTable) {
//             this->fromPermitTable = fromPermitTable;
//         }
//     }


        bool WallVisitorUtils_WallConditionContext::hasPartAlwayTrue() {
            return partAlwayTrue;
        }

        void WallVisitorUtils_WallConditionContext::setPartAlwayTrue(bool partAllowTrue) {
            this->partAlwayTrue = partAllowTrue;
        }

        bool WallVisitorUtils_WallConditionContext::hasPartAlwayFalse() {
            return partAlwayFalse;
        }

        void WallVisitorUtils_WallConditionContext::setPartAlwayFalse(bool partAlwayFalse) {
            this->partAlwayFalse = partAlwayFalse;
        }

        bool WallVisitorUtils_WallConditionContext::hasConstArithmetic() {
            return constArithmetic;
        }

        void WallVisitorUtils_WallConditionContext::setConstArithmetic(bool constArithmetic) {
            this->constArithmetic = constArithmetic;
        }

        bool WallVisitorUtils_WallConditionContext::hasXor() {
            return xor_;
        }

        void WallVisitorUtils_WallConditionContext::setXor(bool xor_) {
            this->xor_ = xor_;
        }

        bool WallVisitorUtils_WallConditionContext::hasBitwise() {
            return bitwise;
        }

        void WallVisitorUtils_WallConditionContext::setBitwise(bool bitwise) {
            this->bitwise = bitwise;
        }


// class WallVisitorUtils {
// public:
//     // static Log LOG = LogFactory.getLog(WallVisitorUtils.class);

std::string WallVisitorUtils::HAS_TRUE_LIKE = "hasTrueLike";

//     static String[] whiteHints = {"LOCAL", "TEMPORARY", "SQL_NO_CACHE", "SQL_CACHE", "HIGH_PRIORITY",
//             "LOW_PRIORITY", "STRAIGHT_JOIN", "SQL_BUFFER_RESULT", "SQL_BIG_RESULT", "SQL_SMALL_RESULT", "DELAYED"};

//     static void check(WallVisitor_ptr visitor, SQLInListExpr x) {
//     }

//     static bool check(WallVisitor_ptr visitor, SQLBinaryOpExpr x) {
//         if (x->getOperator() == SQLBinaryOperator.BooleanOr
//                 || x->getOperator() == SQLBinaryOperator.BooleanAnd) {
//             List<SQLExpr_ptr> groupList = SQLBinaryOpExpr.split(x);
//             for (SQLExpr_ptr item : groupList) {
//                 item.accept(visitor);
//             }
//             return false;
//         }

//         if (x->getOperator() == SQLBinaryOperator.Add
//                 || x->getOperator() == SQLBinaryOperator.Concat) {
//             List<SQLExpr_ptr> groupList = SQLBinaryOpExpr.split(x);
//             if (groupList.size() >= 4) {
//                 int chrCount = 0;
//                 for (int i = 0; i < groupList.size(); ++i) {
//                     SQLExpr_ptr item = groupList.get(i);
//                     if (item instanceof SQLMethodInvokeExpr) {
//                         SQLMethodInvokeExpr methodExpr = (SQLMethodInvokeExpr) item;
//                         String methodName = methodExpr.getMethodName().toLowerCase();
//                         if ("chr".equals(methodName) || "char".equals(methodName)) {
//                             if (methodExpr.getArguments().get(0) instanceof SQLLiteralExpr) {
//                                 chrCount++;
//                             }
//                         }
//                     } else if (item instanceof SQLCharExpr) {
//                         if (((SQLCharExpr) item).getText().length() > 5) {
//                             chrCount = 0;
//                             continue;
//                         }
//                     }

//                     if (chrCount >= 4) {
//                         addViolation(visitor, ErrorCode.EVIL_CONCAT, "evil concat", x);
//                         break;
//                     }
//                 }
//             }
//         }

//         return true;
//     }

//     static bool check(WallVisitor_ptr visitor, SQLBinaryOpExprGroup x) {
//         return true;
//     }

//     static void check(WallVisitor_ptr visitor, SQLCreateTableStatement x) {
//         String tableName = ((SQLName) x->getName()).getSimpleName();
//         WallContext context = WallContext.current();
//         if (context != nullptr) {
//             WallSqlTableStat tableStat = context.getTableStat(tableName);
//             if (tableStat != nullptr) {
//                 tableStat.incrementCreateCount();
//             }
//         }
//     }

//     static void check(WallVisitor_ptr visitor, SQLAlterTableStatement x) {
//         String tableName = ((SQLName) x->getName()).getSimpleName();
//         WallContext context = WallContext.current();
//         if (context != nullptr) {
//             WallSqlTableStat tableStat = context.getTableStat(tableName);
//             if (tableStat != nullptr) {
//                 tableStat.incrementAlterCount();
//             }
//         }
//     }

//     static void check(WallVisitor_ptr visitor, SQLDropTableStatement x) {
//         for (SQLTableSource item : x->getTableSources()) {
//             if (item instanceof SQLExprTableSource) {
//                 SQLExpr_ptr expr = ((SQLExprTableSource) item).getExpr();
//                 String tableName = ((SQLName) expr).getSimpleName();
//                 WallContext context = WallContext.current();
//                 if (context != nullptr) {
//                     WallSqlTableStat tableStat = context.getTableStat(tableName);
//                     if (tableStat != nullptr) {
//                         tableStat.incrementDropCount();
//                     }
//                 }
//             }
//         }
//     }

//     static void check(WallVisitor_ptr visitor, SQLSelectItem x) {
//         SQLExpr_ptr expr = x->getExpr();

//         if (expr instanceof SQLVariantRefExpr) {
//             if (!isTopSelectItem(expr) && "@".equals(((SQLVariantRefExpr) expr).getName())) {
//                 addViolation(visitor, ErrorCode.EVIL_NAME, "@ not allow", x);
//             }
//         }

//         if (visitor.getConfig().isSelectAllColumnAllow()) {
//             return;
//         }

//         if (expr instanceof SQLAllColumnExpr //
//                 && x->getParent() instanceof SQLSelectQueryBlock) {
//             SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) x->getParent();
//             SQLTableSource from = queryBlock.getFrom();

//             if (from instanceof SQLExprTableSource) {
//                 addViolation(visitor, ErrorCode.SELECT_NOT_ALLOW, "'SELECT *' not allow", x);
//             }
//         }
//     }

//     static void check(WallVisitor_ptr visitor, SQLPropertyExpr x) {
//         checkSchema(visitor, x->getOwner());
//     }

//     static void checkInsert(WallVisitor_ptr visitor, SQLInsertInto x) {
//         checkReadOnly(visitor, x->getTableSource());

//         if (!visitor.getConfig().isInsertAllow()) {
//             addViolation(visitor, ErrorCode.INSERT_NOT_ALLOW, "insert not allow", x);
//         }

//         checkInsertForMultiTenant(visitor, x);
//     }

//     static void checkSelelct(WallVisitor_ptr visitor, SQLSelectQueryBlock x) {
//         if (x->getInto() != nullptr) {
//             checkReadOnly(visitor, x->getInto());
//         }

//         if (!visitor.getConfig().isSelectIntoAllow() && x->getInto() != nullptr) {
//             addViolation(visitor, ErrorCode.SELECT_INTO_NOT_ALLOW, "select into not allow", x);
//             return;
//         }

//         List<SQLCommentHint> hints = x->getHintsDirect();
//         if (hints != nullptr
//                 && x->getParent() instanceof SQLUnionQuery
//                 && x == ((SQLUnionQuery) x->getParent()).getRight()
//         ) {
//             for (SQLCommentHint hint : hints) {
//                 String text = hint.getText();
//                 if (text.startsWith("!")) {
//                     addViolation(visitor, ErrorCode.UNION, "union select hint not allow", x);
//                     return;
//                 }
//             }
//         }

//         SQLExpr_ptr where = x->getWhere();
//         if (where != nullptr) {
//             checkCondition(visitor, x->getWhere());

//             Object_ptr whereValue = getConditionValue(visitor, where, visitor.getConfig().isSelectWhereAlwayTrueCheck());

//             if (bool.TRUE == whereValue) {
//                 if (visitor.getConfig().isSelectWhereAlwayTrueCheck()
//                         && visitor.isSqlEndOfComment()
//                         && !isSimpleConstExpr(where)) {
//                     addViolation(visitor, ErrorCode.ALWAYS_TRUE, "select alway true condition not allow", x);
//                 }
//             }
//         }
//         checkSelectForMultiTenant(visitor, x);
//         // checkConditionForMultiTenant(visitor, x->getWhere(), x);
//     }

//     static void checkHaving(WallVisitor_ptr visitor, SQLExpr_ptr x) {
//         if (x == nullptr) {
//             return;
//         }

//         if (bool.TRUE == getConditionValue(visitor, x, visitor.getConfig().isSelectHavingAlwayTrueCheck())) {
//             if (visitor.getConfig().isSelectHavingAlwayTrueCheck()
//                     && visitor.isSqlEndOfComment()
//                     && !isSimpleConstExpr(x)) {
//                 addViolation(visitor, ErrorCode.ALWAYS_TRUE, "having alway true condition not allow", x);
//             }
//         }
//     }

//     static void checkDelete(WallVisitor_ptr visitor, SQLDeleteStatement x) {
//         checkReadOnly(visitor, x->getTableSource());

//         WallConfig config = visitor.getConfig();
//         if (!config.isDeleteAllow()) {
//             addViolation(visitor, ErrorCode.INSERT_NOT_ALLOW, "delete not allow", x);
//             return;
//         }

//         bool hasUsing = false;

//         if (x instanceof MySqlDeleteStatement) {
//             hasUsing = ((MySqlDeleteStatement) x).getUsing() != nullptr;
//         }

//         bool isJoinTableSource = x->getTableSource() instanceof SQLJoinTableSource;
//         if (x->getWhere() == nullptr && (!hasUsing) && !isJoinTableSource) {
//             WallContext context = WallContext.current();
//             if (context != nullptr) {
//                 context.incrementDeleteNoneConditionWarnings();
//             }

//             if (config.isDeleteWhereNoneCheck()) {
//                 addViolation(visitor, ErrorCode.NONE_CONDITION, "delete none condition not allow", x);
//                 return;
//             }
//         }

//         SQLExpr_ptr where = x->getWhere();
//         if (where != nullptr) {
//             checkCondition(visitor, where);

//             if (bool.TRUE == getConditionValue(visitor, where, config.isDeleteWhereAlwayTrueCheck())) {
//                 if (config.isDeleteWhereAlwayTrueCheck() && visitor.isSqlEndOfComment() && !isSimpleConstExpr(where)) {
//                     addViolation(visitor, ErrorCode.ALWAYS_TRUE, "delete alway true condition not allow", x);
//                 }
//             }
//         }

//         // checkConditionForMultiTenant(visitor, x->getWhere(), x);
//     }

//     static bool isSimpleConstExpr(SQLExpr_ptr sqlExpr) {
//         List<SQLExpr_ptr> parts = getParts(sqlExpr);
//         if (parts.isEmpty()) {
//             return false;
//         }

//         for (SQLExpr_ptr part : parts) {
//             if (isFirst(part)) {
//                 Object_ptr evalValue = part.getAttribute(SQLEvalVisitor::EVAL_VALUE);
//                 if (evalValue == nullptr) {
//                     if (part instanceof SQLBooleanExpr) {
//                         evalValue = ((SQLBooleanExpr) part).getBooleanValue();
//                     } else if (part instanceof SQLNumericLiteralExpr) {
//                         evalValue = ((SQLNumericLiteralExpr) part).getNumber();
//                     } else if (part instanceof SQLCharExpr) {
//                         evalValue = ((SQLCharExpr) part).getText();
//                     } else if (part instanceof SQLNCharExpr) {
//                         evalValue = ((SQLNCharExpr) part).getText();
//                     }
//                 }
//                 bool result = SQLEvalVisitorUtils.castToBoolean(evalValue);
//                 if (result != nullptr && result) {
//                     return true;
//                 }
//             }
//             bool isSimpleConstExpr = false;
//             if (part == sqlExpr || part instanceof SQLLiteralExpr) {
//                 isSimpleConstExpr = true;
//             } else if (part instanceof SQLBinaryOpExpr) {
//                 SQLBinaryOpExpr binaryOpExpr = (SQLBinaryOpExpr) part;

//                 if (binaryOpExpr.getOperator() == SQLBinaryOperator.Equality
//                         || binaryOpExpr.getOperator() == SQLBinaryOperator.NotEqual
//                         || binaryOpExpr.getOperator() == SQLBinaryOperator.GreaterThan) {
//                     if (binaryOpExpr.getLeft() instanceof SQLIntegerExpr
//                             && binaryOpExpr.getRight() instanceof SQLIntegerExpr) {
//                         isSimpleConstExpr = true;
//                     }
//                 }
//             }

//             if (!isSimpleConstExpr) {
//                 return false;
//             }
//         }
//         return true;
//     }

//     static void checkCondition(WallVisitor_ptr visitor, SQLExpr_ptr x) {
//         if (x == nullptr) {
//             return;
//         }

//         if (visitor.getConfig().isMustParameterized()) {
//             ExportParameterVisitor exportParameterVisitor = visitor.getProvider().createExportParameterVisitor();
//             x->accept(exportParameterVisitor);

//             if (exportParameterVisitor.getParameters().size() > 0) {
//                 addViolation(visitor, ErrorCode.NOT_PARAMETERIZED, "sql must parameterized", x);
//             }
//         }

//     }

//     static void checkJoinSelectForMultiTenant(WallVisitor_ptr visitor, SQLJoinTableSource join,
//                                                       SQLSelectQueryBlock x) {
//         TenantCallBack tenantCallBack = visitor.getConfig().getTenantCallBack();
//         String tenantTablePattern = visitor.getConfig().getTenantTablePattern();
//         if (tenantCallBack == nullptr && (tenantTablePattern == nullptr || tenantTablePattern.length() == 0)) {
//             return;
//         }

//         SQLTableSource right = join.getRight();
//         if (right instanceof SQLExprTableSource) {
//             SQLExpr_ptr tableExpr = ((SQLExprTableSource) right).getExpr();

//             if (tableExpr instanceof SQLIdentifierExpr) {
//                 String tableName = ((SQLIdentifierExpr) tableExpr).getName();

//                 String alias = nullptr;
//                 String tenantColumn = nullptr;
//                 if (tenantCallBack != nullptr) {
//                     tenantColumn = tenantCallBack.getTenantColumn(StatementType.SELECT, tableName);
//                 }

//                 if (StringUtils.isEmpty(tenantColumn)
//                         && ServletPathMatcher.getInstance().matches(tenantTablePattern, tableName)) {
//                     tenantColumn = visitor.getConfig().getTenantColumn();
//                 }

//                 if (!StringUtils.isEmpty(tenantColumn)) {
//                     alias = right.getAlias();
//                     if (alias == nullptr) {
//                         alias = tableName;
//                     }

//                     SQLExpr_ptr item = nullptr;
//                     if (alias != nullptr) {
//                         item = new SQLPropertyExpr(new SQLIdentifierExpr(alias), tenantColumn);
//                     } else {
//                         item = new SQLIdentifierExpr(tenantColumn);
//                     }
//                     SQLSelectItem selectItem = new SQLSelectItem(item);
//                     x->getSelectList().add(selectItem);
//                     visitor.setSqlModified(true);
//                 }
//             }
//         }
//     }

//     static bool isSelectStatmentForMultiTenant(SQLSelectQueryBlock queryBlock) {
//         SQLObject_ptr parent = queryBlock.getParent();
//         while (parent != nullptr) {
//             if (parent instanceof SQLUnionQuery) {
//                 SQLObject_ptr x = parent;
//                 parent = x->getParent();
//             } else {
//                 break;
//             }
//         }

//         if (!(parent instanceof SQLSelect_ptr)) {
//             return false;
//         }

//         parent = ((SQLSelect_ptr) parent).getParent();
//         if (parent instanceof SQLSelectStatement) {
//             return true;
//         }

//         return false;
//     }

//     static void checkSelectForMultiTenant(WallVisitor_ptr visitor, SQLSelectQueryBlock x) {
//         TenantCallBack tenantCallBack = visitor.getConfig().getTenantCallBack();
//         String tenantTablePattern = visitor.getConfig().getTenantTablePattern();
//         if (tenantCallBack == nullptr && (tenantTablePattern == nullptr || tenantTablePattern.length() == 0)) {
//             return;
//         }

//         if (x == nullptr) {
//             throw new IllegalStateException("x is nullptr");
//         }

//         if (!isSelectStatmentForMultiTenant(x)) {
//             return;
//         }

//         SQLTableSource tableSource = x->getFrom();
//         String alias = nullptr;
//         String matchTableName = nullptr;
//         String tenantColumn = nullptr;
//         if (tableSource instanceof SQLExprTableSource) {
//             SQLExpr_ptr tableExpr = ((SQLExprTableSource) tableSource).getExpr();

//             if (tableExpr instanceof SQLIdentifierExpr) {
//                 String tableName = ((SQLIdentifierExpr) tableExpr).getName();

//                 if (tenantCallBack != nullptr) {
//                     tenantColumn = tenantCallBack.getTenantColumn(StatementType.SELECT, tableName);
//                 }

//                 if (StringUtils.isEmpty(tenantColumn)
//                         && ServletPathMatcher.getInstance().matches(tenantTablePattern, tableName)) {
//                     tenantColumn = visitor.getConfig().getTenantColumn();
//                 }

//                 if (!StringUtils.isEmpty(tenantColumn)) {
//                     matchTableName = tableName;
//                     alias = tableSource.getAlias();
//                 }
//             }
//         } else if (tableSource instanceof SQLJoinTableSource) {
//             SQLJoinTableSource join = (SQLJoinTableSource) tableSource;
//             if (join.getLeft() instanceof SQLExprTableSource) {
//                 SQLExpr_ptr tableExpr = ((SQLExprTableSource) join.getLeft()).getExpr();

//                 if (tableExpr instanceof SQLIdentifierExpr) {
//                     String tableName = ((SQLIdentifierExpr) tableExpr).getName();

//                     if (tenantCallBack != nullptr) {
//                         tenantColumn = tenantCallBack.getTenantColumn(StatementType.SELECT, tableName);
//                     }

//                     if (StringUtils.isEmpty(tenantColumn)
//                             && ServletPathMatcher.getInstance().matches(tenantTablePattern, tableName)) {
//                         tenantColumn = visitor.getConfig().getTenantColumn();
//                     }

//                     if (!StringUtils.isEmpty(tenantColumn)) {
//                         matchTableName = tableName;
//                         alias = join.getLeft().getAlias();

//                         if (alias == nullptr) {
//                             alias = tableName;
//                         }
//                     }
//                 }
//                 checkJoinSelectForMultiTenant(visitor, join, x);
//             } else {
//                 checkJoinSelectForMultiTenant(visitor, join, x);
//             }
//         }

//         if (matchTableName == nullptr) {
//             return;
//         }

//         SQLExpr_ptr item = nullptr;
//         if (alias != nullptr) {
//             item = new SQLPropertyExpr(new SQLIdentifierExpr(alias), tenantColumn);
//         } else {
//             item = new SQLIdentifierExpr(tenantColumn);
//         }
//         SQLSelectItem selectItem = new SQLSelectItem(item);
//         x->getSelectList().add(selectItem);
//         visitor.setSqlModified(true);
//     }

//     static void checkUpdateForMultiTenant(WallVisitor_ptr visitor, SQLUpdateStatement x) {
//         TenantCallBack tenantCallBack = visitor.getConfig().getTenantCallBack();
//         String tenantTablePattern = visitor.getConfig().getTenantTablePattern();
//         if (tenantCallBack == nullptr && (tenantTablePattern == nullptr || tenantTablePattern.length() == 0)) {
//             return;
//         }

//         if (x == nullptr) {
//             throw new IllegalStateException("x is nullptr");
//         }

//         SQLTableSource tableSource = x->getTableSource();
//         String alias = nullptr;
//         String matchTableName = nullptr;
//         String tenantColumn = nullptr;
//         if (tableSource instanceof SQLExprTableSource) {
//             SQLExpr_ptr tableExpr = ((SQLExprTableSource) tableSource).getExpr();
//             if (tableExpr instanceof SQLIdentifierExpr) {
//                 String tableName = ((SQLIdentifierExpr) tableExpr).getName();

//                 if (tenantCallBack != nullptr) {
//                     tenantColumn = tenantCallBack.getTenantColumn(StatementType.UPDATE, tableName);
//                 }
//                 if (StringUtils.isEmpty(tenantColumn)
//                         && ServletPathMatcher.getInstance().matches(tenantTablePattern, tableName)) {
//                     tenantColumn = visitor.getConfig().getTenantColumn();
//                 }

//                 if (!StringUtils.isEmpty(tenantColumn)) {
//                     matchTableName = tableName;
//                     alias = tableSource.getAlias();
//                 }
//             }
//         }

//         if (matchTableName == nullptr) {
//             return;
//         }

//         SQLExpr_ptr item = nullptr;
//         if (alias != nullptr) {
//             item = new SQLPropertyExpr(new SQLIdentifierExpr(alias), tenantColumn);
//         } else {
//             item = new SQLIdentifierExpr(tenantColumn);
//         }
//         SQLExpr_ptr value = generateTenantValue(visitor, alias, StatementType.UPDATE, matchTableName);

//         SQLUpdateSetItem updateSetItem = new SQLUpdateSetItem();
//         updateSetItem.setColumn(item);
//         updateSetItem.setValue(value);

//         x->addItem(updateSetItem);
//         visitor.setSqlModified(true);
//     }

//     static void checkInsertForMultiTenant(WallVisitor_ptr visitor, SQLInsertInto x) {
//         TenantCallBack tenantCallBack = visitor.getConfig().getTenantCallBack();
//         String tenantTablePattern = visitor.getConfig().getTenantTablePattern();
//         if (tenantCallBack == nullptr && (tenantTablePattern == nullptr || tenantTablePattern.length() == 0)) {
//             return;
//         }

//         if (x == nullptr) {
//             throw new IllegalStateException("x is nullptr");
//         }

//         SQLExprTableSource tableSource = x->getTableSource();
//         String alias = nullptr;
//         String matchTableName = nullptr;
//         String tenantColumn = nullptr;
//         SQLExpr_ptr tableExpr = tableSource.getExpr();
//         if (tableExpr instanceof SQLIdentifierExpr) {
//             String tableName = ((SQLIdentifierExpr) tableExpr).getName();

//             if (tenantCallBack != nullptr) {
//                 tenantColumn = tenantCallBack.getTenantColumn(StatementType.INSERT, tableName);
//             }
//             if (StringUtils.isEmpty(tenantColumn)
//                     && ServletPathMatcher.getInstance().matches(tenantTablePattern, tableName)) {
//                 tenantColumn = visitor.getConfig().getTenantColumn();
//             }

//             if (!StringUtils.isEmpty(tenantColumn)) {
//                 matchTableName = tableName;
//                 alias = tableSource.getAlias();
//             }
//         }

//         if (matchTableName == nullptr) {
//             return;
//         }

//         SQLExpr_ptr item = nullptr;
//         if (alias != nullptr) {
//             item = new SQLPropertyExpr(new SQLIdentifierExpr(alias), tenantColumn);
//         } else {
//             item = new SQLIdentifierExpr(tenantColumn);
//         }
//         SQLExpr_ptr value = generateTenantValue(visitor, alias, StatementType.INSERT, matchTableName);

//         // add insert item and value
//         x->getColumns().add(item);

//         List<ValuesClause> valuesClauses = nullptr;
//         ValuesClause valuesClause = nullptr;
//         if (x instanceof MySqlInsertStatement) {
//             valuesClauses = ((MySqlInsertStatement) x).getValuesList();
//         } else if (x instanceof SQLServerInsertStatement) {
//             valuesClauses = ((MySqlInsertStatement) x).getValuesList();
//         } else {
//             valuesClause = x->getValues();
//         }

//         if (valuesClauses != nullptr && valuesClauses.size() > 0) {
//             for (ValuesClause clause : valuesClauses) {
//                 clause.addValue(value);
//             }
//         }
//         if (valuesClause != nullptr) {
//             valuesClause.addValue(value);
//         }

//         // insert .. select
//         SQLSelect_ptr select = x->getQuery();
//         if (select != nullptr) {
//             List<SQLSelectQueryBlock> queryBlocks = splitSQLSelectQuery(select.getQuery());
//             for (SQLSelectQueryBlock queryBlock : queryBlocks) {
//                 queryBlock.getSelectList().add(new SQLSelectItem(value));
//             }
//         }

//         visitor.setSqlModified(true);
//     }

//     static List<SQLSelectQueryBlock> splitSQLSelectQuery(SQLSelectQuery x) {
//         List<SQLSelectQueryBlock> groupList = new ArrayList<SQLSelectQueryBlock>();
//         Stack<SQLSelectQuery> stack = new Stack<SQLSelectQuery>();

//         stack.push(x);
//         do {
//             SQLSelectQuery query = stack.pop();
//             if (query instanceof SQLSelectQueryBlock) {
//                 groupList.add((SQLSelectQueryBlock) query);
//             } else if (query instanceof SQLUnionQuery) {
//                 SQLUnionQuery unionQuery = (SQLUnionQuery) query;
//                 stack.push(unionQuery.getLeft());
//                 stack.push(unionQuery.getRight());
//             }
//         } while (!stack.empty());
//         return groupList;
//     }

//     @Deprecated
//     static void checkConditionForMultiTenant(WallVisitor_ptr visitor, SQLExpr_ptr x, SQLObject_ptr parent) {
//         String tenantTablePattern = visitor.getConfig().getTenantTablePattern();
//         if (tenantTablePattern == nullptr || tenantTablePattern.length() == 0) {
//             return;
//         }

//         if (parent == nullptr) {
//             throw new IllegalStateException("parent is nullptr");
//         }

//         String alias = nullptr;
//         SQLTableSource tableSource;
//         StatementType statementType = nullptr;
//         if (parent instanceof SQLDeleteStatement) {
//             tableSource = ((SQLDeleteStatement) parent).getTableSource();
//             statementType = StatementType.DELETE;
//         } else if (parent instanceof SQLUpdateStatement) {
//             tableSource = ((SQLUpdateStatement) parent).getTableSource();
//             statementType = StatementType.UPDATE;
//         } else if (parent instanceof SQLSelectQueryBlock) {
//             tableSource = ((SQLSelectQueryBlock) parent).getFrom();
//             statementType = StatementType.SELECT;
//         } else {
//             throw new IllegalStateException("not support parent : " + parent.getClass());
//         }

//         String matchTableName = nullptr;
//         if (tableSource instanceof SQLExprTableSource) {
//             SQLExpr_ptr tableExpr = ((SQLExprTableSource) tableSource).getExpr();

//             if (tableExpr instanceof SQLIdentifierExpr) {
//                 String tableName = ((SQLIdentifierExpr) tableExpr).getName();
//                 if (ServletPathMatcher.getInstance().matches(tenantTablePattern, tableName)) {
//                     matchTableName = tableName;
//                     alias = tableSource.getAlias();
//                 }
//             }
//         } else if (tableSource instanceof SQLJoinTableSource) {
//             SQLJoinTableSource join = (SQLJoinTableSource) tableSource;
//             if (join.getLeft() instanceof SQLExprTableSource) {
//                 SQLExpr_ptr tableExpr = ((SQLExprTableSource) join.getLeft()).getExpr();

//                 if (tableExpr instanceof SQLIdentifierExpr) {
//                     String tableName = ((SQLIdentifierExpr) tableExpr).getName();
//                     if (ServletPathMatcher.getInstance().matches(tenantTablePattern, tableName)) {
//                         matchTableName = tableName;
//                         alias = join.getLeft().getAlias();
//                     }
//                 }

//                 checkJoinConditionForMultiTenant(visitor, join, false, statementType);
//             } else {
//                 checkJoinConditionForMultiTenant(visitor, join, true, statementType);
//             }
//         }

//         if (matchTableName == nullptr) {
//             return;
//         }

//         SQLBinaryOpExpr tenantCondition = createTenantCondition(visitor, alias, statementType, matchTableName);

//         SQLExpr_ptr condition;
//         if (x == nullptr) {
//             condition = tenantCondition;
//         } else {
//             condition = new SQLBinaryOpExpr(tenantCondition, SQLBinaryOperator.BooleanAnd, x);
//         }

//         if (parent instanceof SQLDeleteStatement) {
//             SQLDeleteStatement deleteStmt = (SQLDeleteStatement) parent;
//             deleteStmt.setWhere(condition);
//             visitor.setSqlModified(true);
//         } else if (parent instanceof SQLUpdateStatement) {
//             SQLUpdateStatement updateStmt = (SQLUpdateStatement) parent;
//             updateStmt.setWhere(condition);
//             visitor.setSqlModified(true);
//         } else if (parent instanceof SQLSelectQueryBlock) {
//             SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) parent;
//             queryBlock.setWhere(condition);
//             visitor.setSqlModified(true);
//         }
//     }

//     @Deprecated
//     static void checkJoinConditionForMultiTenant(WallVisitor_ptr visitor, SQLJoinTableSource join,
//                                                         bool checkLeft, StatementType statementType) {
//         String tenantTablePattern = visitor.getConfig().getTenantTablePattern();
//         if (tenantTablePattern == nullptr || tenantTablePattern.length() == 0) {
//             return;
//         }

//         SQLExpr_ptr condition = join.getCondition();

//         SQLTableSource right = join.getRight();
//         if (right instanceof SQLExprTableSource) {
//             SQLExpr_ptr tableExpr = ((SQLExprTableSource) right).getExpr();

//             if (tableExpr instanceof SQLIdentifierExpr) {
//                 String tableName = ((SQLIdentifierExpr) tableExpr).getName();
//                 if (ServletPathMatcher.getInstance().matches(tenantTablePattern, tableName)) {
//                     String alias = right.getAlias();
//                     if (alias == nullptr) {
//                         alias = tableName;
//                     }
//                     SQLBinaryOpExpr tenantCondition = createTenantCondition(visitor, alias, statementType, tableName);

//                     if (condition == nullptr) {
//                         condition = tenantCondition;
//                     } else {
//                         condition = new SQLBinaryOpExpr(tenantCondition, SQLBinaryOperator.BooleanAnd, condition);
//                     }
//                 }
//             }
//         }

//         if (condition != join.getCondition()) {
//             join.setCondition(condition);
//             visitor.setSqlModified(true);
//         }
//     }

//     @Deprecated
//     static SQLBinaryOpExpr createTenantCondition(WallVisitor_ptr visitor, String alias,
//                                                          StatementType statementType, String tableName) {
//         SQLExpr_ptr left, right;
//         if (alias != nullptr) {
//             left = new SQLPropertyExpr(new SQLIdentifierExpr(alias), visitor.getConfig().getTenantColumn());
//         } else {
//             left = new SQLIdentifierExpr(visitor.getConfig().getTenantColumn());
//         }
//         right = generateTenantValue(visitor, alias, statementType, tableName);

//         SQLBinaryOpExpr tenantCondition = new SQLBinaryOpExpr(left, SQLBinaryOperator.Equality, right);
//         return tenantCondition;
//     }

//     static SQLExpr_ptr generateTenantValue(WallVisitor_ptr visitor, String alias, StatementType statementType,
//                                                String tableName) {
//         SQLExpr_ptr value;
//         TenantCallBack callBack = visitor.getConfig().getTenantCallBack();
//         if (callBack != nullptr) {
//             WallProvider.setTenantValue(callBack.getTenantValue(statementType, tableName));
//         }

//         Object_ptr tenantValue = WallProvider.getTenantValue();
//         if (tenantValue instanceof Number) {
//             value = new SQLNumberExpr((Number) tenantValue);
//         } else if (tenantValue instanceof String) {
//             value = new SQLCharExpr((String) tenantValue);
//         } else {
//             throw new IllegalStateException("tenant value not support type " + tenantValue);
//         }

//         return value;
//     }

//     static void checkReadOnly(WallVisitor_ptr visitor, SQLTableSource tableSource) {
//         if (tableSource instanceof SQLExprTableSource) {
//             String tableName = nullptr;
//             SQLExpr_ptr tableNameExpr = ((SQLExprTableSource) tableSource).getExpr();
//             if (tableNameExpr instanceof SQLName) {
//                 tableName = ((SQLName) tableNameExpr).getSimpleName();
//             }

//             bool readOnlyValid = visitor.getProvider().checkReadOnlyTable(tableName);
//             if (!readOnlyValid) {
//                 addViolation(visitor, ErrorCode.READ_ONLY, "table readonly : " + tableName, tableSource);
//             }
//         } else if (tableSource instanceof SQLJoinTableSource) {
//             SQLJoinTableSource join = (SQLJoinTableSource) tableSource;

//             checkReadOnly(visitor, join.getLeft());
//             checkReadOnly(visitor, join.getRight());
//         }
//     }

//     static void checkUpdate(WallVisitor_ptr visitor, SQLUpdateStatement x) {
//         checkReadOnly(visitor, x->getTableSource());

//         WallConfig config = visitor.getConfig();
//         if (!config.isUpdateAllow()) {
//             addViolation(visitor, ErrorCode.UPDATE_NOT_ALLOW, "update not allow", x);
//             return;
//         }

//         SQLExpr_ptr where = x->getWhere();
//         if (where == nullptr) {
//             WallContext context = WallContext.current();
//             if (context != nullptr) {
//                 context.incrementUpdateNoneConditionWarnings();
//             }

//             if (config.isUpdateWhereNoneCheck()) {
//                 if (x instanceof MySqlUpdateStatement) {
//                     MySqlUpdateStatement mysqlUpdate = (MySqlUpdateStatement) x;
//                     if (mysqlUpdate.getLimit() == nullptr) {
//                         addViolation(visitor, ErrorCode.NONE_CONDITION, "update none condition not allow", x);
//                         return;
//                     }
//                 } else {
//                     addViolation(visitor, ErrorCode.NONE_CONDITION, "update none condition not allow", x);
//                     return;
//                 }
//             }
//         } else {
//             checkCondition(visitor, where);

//             if (bool.TRUE == getConditionValue(visitor, where, config.isUpdateWhereAlayTrueCheck())) {
//                 if (config.isUpdateWhereAlayTrueCheck() && visitor.isSqlEndOfComment() && !isSimpleConstExpr(where)) {
//                     addViolation(visitor, ErrorCode.ALWAYS_TRUE, "update alway true condition not allow", x);
//                 }
//             }

//             SQLName table = x->getTableName();
//             if (table == nullptr) {
//                 return;
//             }

//             String tableName = table.getSimpleName();
//             Set<String> updateCheckColumns = config.getUpdateCheckTable(tableName);
//             bool isUpdateCheckTable = updateCheckColumns != nullptr && !updateCheckColumns.isEmpty();

//             WallUpdateCheckHandler updateCheckHandler = config.getUpdateCheckHandler();
//             if (isUpdateCheckTable && updateCheckHandler != nullptr) {
//                 String checkColumn = updateCheckColumns.iterator().next();

//                 SQLExpr_ptr valueExpr = nullptr;
//                 for (SQLUpdateSetItem item : x->getItems()) {
//                     if (item.columnMatch(checkColumn)) {
//                         valueExpr = item.getValue();
//                         break;
//                     }
//                 }

//                 if (valueExpr != nullptr) {
//                     List<SQLExpr_ptr> conditions;
//                     if (where instanceof SQLBinaryOpExpr) {
//                         conditions = SQLBinaryOpExpr.split((SQLBinaryOpExpr) where, SQLBinaryOperator.BooleanAnd);
//                     } else if (where instanceof SQLBinaryOpExprGroup) {
//                         conditions = new ArrayList<SQLExpr_ptr>();
//                         for (SQLExpr_ptr each : ((SQLBinaryOpExprGroup) where).getItems()) {
//                             if (each instanceof SQLBinaryOpExpr) {
//                                 conditions.addAll(SQLBinaryOpExpr.split((SQLBinaryOpExpr) each, SQLBinaryOperator.BooleanAnd));
//                             } else if (each instanceof SQLInListExpr) {
//                                 conditions.add(each);
//                             }
//                         }
//                     } else {
//                         conditions = new ArrayList<SQLExpr_ptr>();
//                         conditions.add(where);
//                     }

//                     List<SQLExpr_ptr> filterValueExprList = new ArrayList<SQLExpr_ptr>();
//                     for (SQLExpr_ptr condition : conditions) {
//                         if (condition instanceof SQLBinaryOpExpr) {
//                             SQLBinaryOpExpr binaryCondition = (SQLBinaryOpExpr) condition;
//                             if (binaryCondition.getOperator() == SQLBinaryOperator.Equality
//                                     && binaryCondition.conditionContainsColumn(checkColumn)) {
//                                 SQLExpr_ptr left = binaryCondition.getLeft();
//                                 SQLExpr_ptr right = binaryCondition.getRight();

//                                 if (left instanceof SQLValuableExpr || left instanceof SQLVariantRefExpr) {
//                                     filterValueExprList.add(left);
//                                 } else if (right instanceof SQLValuableExpr || right instanceof SQLVariantRefExpr) {
//                                     filterValueExprList.add(right);
//                                 }
//                             }
//                         } else if (condition instanceof SQLInListExpr) {
//                             SQLInListExpr listExpr = (SQLInListExpr) condition;
//                             if (listExpr.getExpr() instanceof SQLIdentifierExpr) {
//                                 SQLIdentifierExpr nameExpr = (SQLIdentifierExpr) listExpr.getExpr();
//                                 if (nameExpr.getName().equals(checkColumn)) {
//                                     filterValueExprList.addAll(((SQLInListExpr) condition).getTargetList());
//                                 }
//                             }
//                         }
//                     }

//                     bool allValue = valueExpr instanceof SQLValuableExpr;
//                     if (allValue) {
//                         for (SQLExpr_ptr filterValue : filterValueExprList) {
//                             if (!(filterValue instanceof SQLValuableExpr)) {
//                                 allValue = false;
//                                 break;
//                             }
//                         }
//                     }

//                     if (allValue) {
//                         Object_ptr setValue = ((SQLValuableExpr) valueExpr).getValue();
//                         Object_list_ptr filterValues = new ArrayList<Object_ptr>(filterValueExprList.size());
//                         for (SQLExpr_ptr expr : filterValueExprList) {
//                             filterValues.add(((SQLValuableExpr) expr).getValue());
//                         }
//                         filterValues = new ArrayList(new HashSet(filterValues));
//                         bool validate = updateCheckHandler.check(tableName, checkColumn, setValue, filterValues);
//                         if (!validate) {
//                             visitor.addViolation(new IllegalSQLObjectViolation(ErrorCode.UPDATE_CHECK_FAIL, "update check failed.", visitor.toSQL(x)));
//                         }
//                     } else {
//                         visitor.addWallUpdateCheckItem(new WallUpdateCheckItem(tableName, checkColumn, valueExpr, filterValueExprList));
//                     }
//                     //updateCheckHandler.check(tableName, checkColumn)
//                 }
//             }
//         }

//         checkUpdateForMultiTenant(visitor, x);
//     }

//     static Object_ptr getValue(WallVisitor_ptr visitor, SQLBinaryOpExprGroup x) {
//         List<SQLExpr_ptr> groupList = x->getItems();

//         if (x->getOperator() == SQLBinaryOperator.BooleanOr) {
//             return getValue_or(visitor, groupList);
//         }

//         if (x->getOperator() == SQLBinaryOperator.BooleanAnd) {
//             return getValue_and(visitor, groupList);
//         }

//         return nullptr;
//     }

//     static Object_ptr getValue(WallVisitor_ptr visitor, SQLBinaryOpExpr x) {
//         if (x->getOperator() == SQLBinaryOperator.BooleanOr) {
//             List<SQLExpr_ptr> groupList = SQLBinaryOpExpr.split(x);

//             return getValue_or(visitor, groupList);
//         }

//         if (x->getOperator() == SQLBinaryOperator.BooleanAnd) {
//             List<SQLExpr_ptr> groupList = SQLBinaryOpExpr.split(x);
//             return getValue_and(visitor, groupList);
//         }

//         bool checkCondition = visitor != nullptr
//                 && (!visitor.getConfig().isConstArithmeticAllow()
//                 || !visitor.getConfig().isConditionOpBitwseAllow() || !visitor.getConfig().isConditionOpXorAllow());

//         if (x->getLeft() instanceof SQLName) {
//             if (x->getRight() instanceof SQLName) {
//                 if (x->getLeft().toString().equalsIgnoreCase(x->getRight().toString())) {
//                     switch (x->getOperator()) {
//                         case Equality:
//                         case Like:
//                             return bool.TRUE;
//                         case NotEqual:
//                         case GreaterThan:
//                         case GreaterThanOrEqual:
//                         case LessThan:
//                         case LessThanOrEqual:
//                         case LessThanOrGreater:
//                         case NotLike:
//                             return bool.FALSE;
//                         default:
//                             break;
//                     }
//                 }
//             } else if (!checkCondition) {
//                 switch (x->getOperator()) {
//                     case Equality:
//                     case NotEqual:
//                     case GreaterThan:
//                     case GreaterThanOrEqual:
//                     case LessThan:
//                     case LessThanOrEqual:
//                     case LessThanOrGreater:
//                         return nullptr;
//                     default:
//                         break;
//                 }
//             }
//         }

//         if (x->getLeft() instanceof SQLValuableExpr && x->getRight() instanceof SQLValuableExpr) {
//             Object_ptr leftValue = ((SQLValuableExpr) x->getLeft()).getValue();
//             Object_ptr rightValue = ((SQLValuableExpr) x->getRight()).getValue();
//             if (x->getOperator() == SQLBinaryOperator.Equality) {
//                 bool evalValue = SQLEvalVisitorUtils.eq(leftValue, rightValue);
//                 x->putAttribute(SQLEvalVisitor::EVAL_VALUE, evalValue);
//                 return evalValue;
//             } else if (x->getOperator() == SQLBinaryOperator.NotEqual) {
//                 bool evalValue = SQLEvalVisitorUtils.eq(leftValue, rightValue);
//                 x->putAttribute(SQLEvalVisitor::EVAL_VALUE, !evalValue);
//                 return !evalValue;
//             }
//         }

//         Object_ptr leftResult = getValue(visitor, x->getLeft());
//         Object_ptr rightResult = getValue(visitor, x->getRight());

//         if (x->getOperator() == SQLBinaryOperator.Like && leftResult instanceof String && leftResult.equals(rightResult)) {
//             addViolation(visitor, ErrorCode.SAME_CONST_LIKE, "same const like", x);
//         }

//         if (x->getOperator() == SQLBinaryOperator.Like || x->getOperator() == SQLBinaryOperator.NotLike) {
//             WallContext context = WallContext.current();
//             if (context != nullptr) {
//                 if (rightResult instanceof Number || leftResult instanceof Number) {
//                     context.incrementLikeNumberWarnings();
//                 }
//             }
//         }

//         DbType dbType = nullptr;
//         WallContext wallContext = WallContext.current();
//         if (wallContext != nullptr) {
//             dbType = wallContext.getDbType();
//         }

//         return eval(visitor, dbType, x, Collections.emptyList());
//     }

//     static Object_ptr getValue_or(WallVisitor_ptr visitor, List<SQLExpr_ptr> groupList) {
//         bool allFalse = true;
//         for (int i = groupList.size() - 1; i >= 0; --i) {
//             SQLExpr_ptr item = groupList.get(i);
//             Object_ptr result = getValue(visitor, item);
//             bool booleanVal = SQLEvalVisitorUtils.castToBoolean(result);
//             if (booleanVal != nullptr && booleanVal.booleanValue()) {
//                 WallConditionContext wallContext = WallVisitorUtils.getWallConditionContext();
//                 if (wallContext != nullptr && !isFirst(item)) {
//                     wallContext.setPartAlwayTrue(true);
//                 }
//                 return true;
//             }

//             if (booleanVal == nullptr) {
//                 allFalse = false;
//                 break;
//             }
//         }

//         if (allFalse) {
//             return false;
//         }

//         return nullptr;
//     }

//     static Object_ptr getValue_and(WallVisitor_ptr visitor, List<SQLExpr_ptr> groupList) {
//         int dalConst = 0;
//         bool allTrue = bool.TRUE;
//         for (int i = groupList.size() - 1; i >= 0; --i) {
//             SQLExpr_ptr item = groupList.get(i);
//             Object_ptr result = getValue(visitor, item);
//             bool booleanVal = SQLEvalVisitorUtils.castToBoolean(result);

//             if (bool.TRUE == booleanVal) {
//                 WallConditionContext wallContext = WallVisitorUtils.getWallConditionContext();
//                 if (wallContext != nullptr && !isFirst(item)) {
//                     wallContext.setPartAlwayTrue(true);
//                 }
//                 dalConst++;
//             } else if (bool.FALSE == booleanVal) {
//                 WallConditionContext wallContext = WallVisitorUtils.getWallConditionContext();
//                 if (wallContext != nullptr && !isFirst(item)) {
//                     wallContext.setPartAlwayFalse(true);
//                 }
//                 allTrue = bool.FALSE;
//                 dalConst++;
//             } else {
//                 if (allTrue != bool.FALSE) {
//                     allTrue = nullptr;
//                 }
//                 dalConst = 0;
//             }

//             if (dalConst == 2 && visitor != nullptr && !visitor.getConfig().isConditionDoubleConstAllow()) {
//                 addViolation(visitor, ErrorCode.DOUBLE_CONST_CONDITION, "double const condition", item);
//             }
//         }

//         if (bool.TRUE == allTrue) {
//             return true;
//         } else if (bool.FALSE == allTrue) {
//             return false;
//         }
//         return nullptr;
//     }

//     static SQLExpr_ptr getFirst(SQLExpr_ptr x) {
//         if (x instanceof SQLBinaryOpExpr) {
//             SQLBinaryOpExpr binary = (SQLBinaryOpExpr) x;
//             if (binary.getOperator() == SQLBinaryOperator.BooleanAnd
//                     || binary.getOperator() == SQLBinaryOperator.BooleanOr) {
//                 return getFirst(((SQLBinaryOpExpr) x).getLeft());
//             }
//         }

//         return x;
//     }

//     static List<SQLExpr_ptr> getParts(SQLExpr_ptr x) {
//         List<SQLExpr_ptr> exprs = new ArrayList<SQLExpr_ptr>();
//         exprs.add(x);

//         while (true) {
//             List<SQLExpr_ptr> tmp = partExpr(exprs);

//             if (tmp.size() == exprs.size()) {
//                 break;
//             }
//             exprs = tmp;
//         }

//         return exprs;
//     }

//     static List<SQLExpr_ptr> partExpr(List<SQLExpr_ptr> exprs) {
//         List<SQLExpr_ptr> partList = new ArrayList<SQLExpr_ptr>();

//         for (SQLExpr_ptr x : exprs) {
//             if (x instanceof SQLBinaryOpExpr) {
//                 SQLBinaryOpExpr binary = (SQLBinaryOpExpr) x;
//                 if (binary.getOperator() == SQLBinaryOperator.BooleanAnd
//                         || binary.getOperator() == SQLBinaryOperator.BooleanOr) {
//                     partList.add(((SQLBinaryOpExpr) x).getLeft());
//                     partList.add(((SQLBinaryOpExpr) x).getRight());

//                     continue;
//                 }
//             }
//             partList.add(x);
//         }
//         return partList;
//     }

//     static bool isFirst(SQLObject_ptr x) {
//         if (x == nullptr) {
//             return true;
//         }

//         for (; ; ) {
//             SQLObject_ptr parent = x->getParent();
//             if (!(parent instanceof SQLExpr_ptr)) {
//                 return true;
//             }

//             if (parent instanceof SQLBinaryOpExprGroup) {
//                 if (x != ((SQLBinaryOpExprGroup) parent).getItems().get(0)) {
//                     return false;
//                 }
//             }

//             if (parent instanceof SQLBinaryOpExpr) {
//                 SQLBinaryOpExpr binaryExpr = (SQLBinaryOpExpr) parent;
//                 if (x == binaryExpr.getRight()) {
//                     return false;
//                 }
//             }
//             x = parent;
//         }
//     }

//     static bool hasWhere(SQLSelectQuery selectQuery) {
//         if (selectQuery instanceof SQLSelectQueryBlock) {
//             return ((SQLSelectQueryBlock) selectQuery).getWhere() != nullptr;
//         } else if (selectQuery instanceof SQLUnionQuery) {
//             SQLUnionQuery union = (SQLUnionQuery) selectQuery;
//             return hasWhere(union.getLeft()) || hasWhere(union.getRight());
//         }
//         return false;
//     }

//     static bool checkSqlExpr(SQLExpr_ptr x) { // check groupby, orderby, limit
//         if (x == nullptr) {
//             return false;
//         }

//         SQLObject_ptr obj = x;
//         for (; ; ) {
//             SQLObject_ptr parent = obj.getParent();

//             if (parent == nullptr) {
//                 return false;
//             }

//             if (parent instanceof SQLSelectGroupByClause) {
//                 return true;
//             } else if (parent instanceof SQLOrderBy) {
//                 return true;
//             } else if (parent instanceof SQLLimit) {
//                 return true;
//             } else if (parent instanceof MySqlOrderingExpr) {
//                 return true;
//             }

//             obj = parent;
//         }
//     }

//     static bool isWhereOrHaving(SQLObject_ptr x) {
//         if (x == nullptr) {
//             return false;
//         }

//         for (; ; ) {
//             SQLObject_ptr parent = x->getParent();

//             if (parent == nullptr) {
//                 return false;
//             }

//             if (parent instanceof SQLJoinTableSource) {
//                 SQLJoinTableSource joinTableSource = (SQLJoinTableSource) parent;
//                 if (joinTableSource.getCondition() == x) {
//                     return true;
//                 }

//             }

//             if (parent instanceof SQLUnionQuery) {
//                 SQLUnionQuery union = (SQLUnionQuery) parent;
//                 if (union.getRight() == x && hasWhere(union.getLeft())) {
//                     return true;
//                 }
//             }

//             if (parent instanceof SQLSelectQueryBlock) {
//                 SQLSelectQueryBlock query = (SQLSelectQueryBlock) parent;
//                 if (query.getWhere() == x) {
//                     return true;
//                 }
//             }

//             if (parent instanceof SQLDeleteStatement) {
//                 SQLDeleteStatement delete = (SQLDeleteStatement) parent;
//                 if (delete.getWhere() == x) {
//                     return true;
//                 } else {
//                     return false;
//                 }
//             }

//             if (parent instanceof SQLUpdateStatement) {
//                 SQLUpdateStatement update = (SQLUpdateStatement) parent;
//                 if (update.getWhere() == x) {
//                     return true;
//                 } else {
//                     return false;
//                 }
//             }

//             if (parent instanceof SQLSelectGroupByClause) {
//                 SQLSelectGroupByClause groupBy = (SQLSelectGroupByClause) parent;
//                 if (x == groupBy.getHaving()) {
//                     return true;
//                 } else {
//                     return false;
//                 }
//             }

//             x = parent;
//         }
//     }

thread_local WallVisitorUtils_WallConditionContext_ptr WallVisitorUtils::wallConditionContextLocal = WallVisitorUtils_WallConditionContext_ptr(new WallVisitorUtils_WallConditionContext());
//     static ThreadLocal<WallTopStatementContext> wallTopStatementContextLocal = new ThreadLocal<WallTopStatementContext>();

WallVisitorUtils_WallConditionContext_ptr WallVisitorUtils::getWallConditionContext() {
        return wallConditionContextLocal;
    }

//     static WallTopStatementContext getWallTopStatementContext() {
//         return wallTopStatementContextLocal.get();
//     }

//     static void clearWallTopStatementContext() {
//         wallTopStatementContextLocal.set(nullptr);
//     }

//     static void initWallTopStatementContext() {
//         wallTopStatementContextLocal.set(new WallTopStatementContext());
//     }

//     static Object_ptr getConditionValue(WallVisitor_ptr visitor, SQLExpr_ptr x, bool alwayTrueCheck) {
//         WallConditionContext old = wallConditionContextLocal.get();
//         try {
//             wallConditionContextLocal.set(new WallConditionContext());
//             Object_ptr value = getValue(visitor, x);

//             WallConditionContext current = wallConditionContextLocal.get();
//             WallContext context = WallContext.current();
//             if (context != nullptr) {
//                 if (current.hasPartAlwayTrue() || bool.TRUE == value) {
//                     if (!isFirst(x)) {
//                         context.incrementWarnings();
//                     }
//                 }
//             }

//             if (current.hasPartAlwayTrue()
//                     && !visitor.getConfig().isConditionAndAlwayTrueAllow()) {
//                 addViolation(visitor, ErrorCode.ALWAYS_TRUE, "part alway true condition not allow", x);
//             }

//             if (current.hasPartAlwayFalse()
//                     && !visitor.getConfig().isConditionAndAlwayFalseAllow()) {
//                 addViolation(visitor, ErrorCode.ALWAYS_FALSE, "part alway false condition not allow", x);
//             }

//             if (current.hasConstArithmetic()
//                     && !visitor.getConfig().isConstArithmeticAllow()) {
//                 addViolation(visitor, ErrorCode.CONST_ARITHMETIC, "const arithmetic not allow", x);
//             }

//             if (current.hasXor() && !visitor.getConfig().isConditionOpXorAllow()) {
//                 addViolation(visitor, ErrorCode.XOR, "xor_ not allow", x);
//             }

//             if (current.hasBitwise() && !visitor.getConfig().isConditionOpBitwseAllow()) {
//                 addViolation(visitor, ErrorCode.BITWISE, "bitwise operator not allow", x);
//             }

//             return value;
//         } finally {
//             wallConditionContextLocal.set(old);
//         }
//     }

Object_ptr WallVisitorUtils::getValueFromAttributes(WallVisitor_ptr visitor, SQLObject_ptr sqlObject) {
        if (sqlObject == nullptr) {
            return nullptr;
        }

        if (visitor != nullptr && visitor->getConfig()->isConditionLikeTrueAllow()
                && sqlObject->getAttributes()->count(HAS_TRUE_LIKE) != 0) {
            return nullptr;
        }
        return sqlObject->getAttribute(SQLEvalVisitor::EVAL_VALUE->c_str());
    }

 Object_ptr WallVisitorUtils::getValue(SQLExpr_ptr x) {
        return getValue(nullptr, x);
    }

Object_ptr WallVisitorUtils::getValue(WallVisitor_ptr visitor, SQLExpr_ptr x) {
        if (x != nullptr && x->containsAttribute(SQLEvalVisitor::EVAL_VALUE)) {
            return getValueFromAttributes(visitor, x);
        }

        if (instanceof<SQLExpr,SQLBinaryOpExpr>(x)  ) {
            return getValue(visitor, std::dynamic_pointer_cast<SQLBinaryOpExpr>(x) );
        }

        if (instanceof<SQLExpr,SQLBinaryOpExprGroup>(x) ) {
            return getValue(visitor, std::dynamic_pointer_cast<SQLBinaryOpExprGroup>(x) );
        }

        if (instanceof<SQLExpr,SQLBooleanExpr>(x) ) {
            return Object_ptr(new Object((std::dynamic_pointer_cast<SQLBooleanExpr>(x) )->getBooleanValue()));
        }

        if (instanceof<SQLExpr,SQLNumericLiteralExpr>(x) ) {
            return Object_ptr(new Object((std::dynamic_pointer_cast<SQLNumericLiteralExpr>(x) )->getNumber()));
        }

        if (instanceof<SQLExpr,SQLCharExpr>(x) ) {
            return  Object_ptr(new Object((std::dynamic_pointer_cast<SQLCharExpr>(x) )->getText()->c_str()));
        }

        if (instanceof<SQLExpr,SQLNCharExpr>(x) ) {
            return Object_ptr(new Object((std::dynamic_pointer_cast<SQLNCharExpr>(x) )->getText()->c_str()));
        }

        if (instanceof<SQLExpr,SQLNotExpr>(x) ) {
            Object_ptr result = getValue(visitor, (std::dynamic_pointer_cast<SQLNotExpr>(x) )->getExpr());
            if (result->getType() == Object::ParamType::BOOL) {
                return Object_ptr(new Object(!result->getBool()));
            }
        }

        if (instanceof<SQLExpr,SQLQueryExpr>(x) ) {
            if (isSimpleCountTableSource(visitor, (std::dynamic_pointer_cast<SQLQueryExpr>(x) )->getSubQuery())) {
                return Object_ptr(new Object(1));
            }

            if (isSimpleCaseTableSource(visitor, (std::dynamic_pointer_cast<SQLQueryExpr>(x) )->getSubQuery())) {
                SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>((std::dynamic_pointer_cast<SQLQueryExpr>(x) )->getSubQuery()->getQuery());
                SQLCaseExpr_ptr caseExpr = std::dynamic_pointer_cast<SQLCaseExpr>( (*(queryBlock->getSelectList()->begin()))->getExpr());

                Object_ptr result = getValue(caseExpr);

                if (visitor != nullptr && !visitor->getConfig()->isCaseConditionConstAllow()) {
                    bool leftIsName = false;
                    if (instanceof<SQLObject,SQLBinaryOpExpr>(x->getParent())  ) {
                        SQLExpr_ptr left = (std::dynamic_pointer_cast<SQLBinaryOpExpr>( x->getParent()))->getLeft();
                        if (instanceof<SQLExpr,SQLName>(left)  ) {
                            leftIsName = true;
                        }
                    }

                    if (!leftIsName && result != nullptr) {
                        addViolation(visitor, ErrorCode::CONST_CASE_CONDITION, "const case condition", caseExpr);
                    }
                }

                return result;
            }
        }

        DbType_ptr dbType = nullptr;
        if (visitor != nullptr) {
            dbType = visitor->getDbType();
        }

        if (instanceof<SQLExpr,SQLMethodInvokeExpr>(x) //
                || instanceof<SQLExpr,SQLBetweenExpr>(x)  //
                || instanceof<SQLExpr,SQLInListExpr>(x)  //
                || instanceof<SQLExpr,SQLUnaryExpr>(x)  //
        ) {
            Object_list_ptr tmp = std::make_shared<std::list<Object_ptr>>();
            return eval(visitor, dbType, x, tmp);
        }

        if (instanceof<SQLExpr,SQLCaseExpr>(x) ) {
            if (visitor != nullptr && !visitor->getConfig()->isCaseConditionConstAllow()) {
                SQLCaseExpr_ptr caseExpr = std::dynamic_pointer_cast<SQLCaseExpr>(x) ;

                bool leftIsName = false;
                if (instanceof<SQLObject,SQLBinaryOpExpr>(caseExpr->getParent())  ) {
                    SQLExpr_ptr left = (std::dynamic_pointer_cast<SQLBinaryOpExpr>( caseExpr->getParent()))->getLeft();
                    if ( instanceof <SQLExpr,SQLName>(left)) {
                        leftIsName = true;
                    }
                }

                if (!leftIsName && caseExpr->getValueExpr() == nullptr && caseExpr->getItems()->size() > 0) {
                    SQLCaseExpr_Item_ptr item = *(caseExpr->getItems()->begin());
                    Object_ptr conditionVal = getValue(visitor, item->getConditionExpr());
                    Object_ptr itemVal = getValue(visitor, item->getValueExpr());
                    if (conditionVal->getType() == Object::ParamType::BOOL && itemVal != nullptr) {
                        addViolation(visitor, ErrorCode::CONST_CASE_CONDITION, "const case condition", caseExpr);
                    }
                }
            }

            Object_list_ptr tmp = std::make_shared<std::list<Object_ptr>>();
            return eval(visitor, dbType, x, tmp);
        }

        return nullptr;
    }

Object_ptr WallVisitorUtils::eval(WallVisitor_ptr wallVisitor, DbType_ptr dbType, SQLObject_ptr sqlObject, Object_list_ptr parameters) {
        SQLEvalVisitor_ptr visitor = SQLEvalVisitorUtils::createEvalVisitor(dbType);
        visitor->setParameters(parameters);
        visitor->registerFunction("rand", Nil::instance());
        visitor->registerFunction("sin", Nil::instance());
        visitor->registerFunction("cos", Nil::instance());
        visitor->registerFunction("asin", Nil::instance());
        visitor->registerFunction("acos", Nil::instance());
        sqlObject->accept(visitor);

        if (instanceof<SQLObject,SQLNumericLiteralExpr>(sqlObject)  ) {
            return Object_ptr(new Object((std::dynamic_pointer_cast<SQLNumericLiteralExpr>(sqlObject) )->getNumber()));
        }
        return getValueFromAttributes(wallVisitor, sqlObject);
    }

//     static bool isSimpleCountTableSource(WallVisitor_ptr visitor, SQLTableSource tableSource) {
//         if (!(tableSource instanceof SQLSubqueryTableSource)) {
//             return false;
//         }

//         SQLSubqueryTableSource subQuery = (SQLSubqueryTableSource) tableSource;

//         return isSimpleCountTableSource(visitor, subQuery.getSelect());
//     }

bool WallVisitorUtils::isSimpleCountTableSource(WallVisitor_ptr visitor, SQLSelect_ptr select) {
        SQLSelectQuery_ptr query = select->getQuery();

        if (instanceof<SQLSelectQuery,SQLSelectQueryBlock>(query)  ) {
            SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(query) ;

            bool allawTrueWhere = false;

            if (queryBlock->getWhere() == nullptr) {
                allawTrueWhere = true;
            } else {
                Object_ptr whereValue = getValue(visitor, queryBlock->getWhere());
                if (whereValue->getType() == Object::ParamType::BOOL) {
                    if (whereValue->getBool()) {
                        allawTrueWhere = true;
                    } else {
                        return false;
                    }
                }
            }
            bool simpleCount = false;
            if (queryBlock->getSelectList()->size() == 1) {
                SQLExpr_ptr selectItemExpr = (*(queryBlock->getSelectList()->begin()))->getExpr();
                if (instanceof<SQLExpr,SQLAggregateExpr>(selectItemExpr)  ) {
                    if ((std::dynamic_pointer_cast<SQLAggregateExpr>(selectItemExpr) )->methodNameHashCode64() == FnvHash::Constants::COUNT) {
                        simpleCount = true;
                    }
                }
            }

            if (allawTrueWhere && simpleCount) {
                return true;
            }
        }

        return false;
    }

bool WallVisitorUtils::isSimpleCaseTableSource(WallVisitor_ptr visitor, SQLSelect_ptr select) {
        SQLSelectQuery_ptr query = select->getQuery();

        if ( instanceof <SQLSelectQuery,SQLSelectQueryBlock>(query)) {
            SQLSelectQueryBlock_ptr queryBlock = std::dynamic_pointer_cast<SQLSelectQueryBlock>(query) ;

            if (queryBlock->getWhere() != nullptr) {
                Object_ptr whereValue = getValue(visitor, queryBlock->getWhere());
                if (whereValue->getType() == Object::ParamType::BOOL) {
                    if (!whereValue->getBool()) {
                        return false;
                    }
                }
            }
            bool simpleCase = false;
            if (queryBlock->getSelectList()->size() == 1) {
                SQLExpr_ptr selectItemExpr = (*(queryBlock->getSelectList()->begin()))->getExpr();
                if ( instanceof <SQLExpr,SQLCaseExpr>(selectItemExpr)) {
                    simpleCase = true;
                }
            }

            if (simpleCase) {
                return true;
            }
        }

        return false;
    }

//     static void checkFunctionInTableSource(WallVisitor_ptr visitor, SQLMethodInvokeExpr x) {
//         WallTopStatementContext topStatementContext = wallTopStatementContextLocal.get();
//         if (topStatementContext != nullptr && (topStatementContext.fromSysSchema || topStatementContext.fromSysTable)) {
//             return;
//         }

//         checkSchema(visitor, x->getOwner());

//         String methodName = x->getMethodName().toLowerCase();
//         if (!visitor.getProvider().checkDenyTable(methodName)) {
//             if (isTopStatementWithTableSource(x) || isFirstSelectTableSource(x)) {
//                 if (topStatementContext != nullptr) {
//                     topStatementContext.setFromSysSchema(bool.TRUE);
//                     clearViolation(visitor);
//                 }
//             }
//         }
//     }

//     static void checkFunction(WallVisitor_ptr visitor, SQLMethodInvokeExpr x) {
//         WallTopStatementContext topStatementContext = wallTopStatementContextLocal.get();
//         if (topStatementContext != nullptr && (topStatementContext.fromSysSchema || topStatementContext.fromSysTable)) {
//             return;
//         }

//         String methodName = x->getMethodName().toLowerCase();
//         SQLExpr_ptr owner = x->getOwner();

//         WallProvider provider = visitor.getProvider();

//         if (!visitor.getConfig().isFunctionCheck()) {
//             return;
//         }

//         WallContext context = WallContext.current();
//         if (context != nullptr) {
//             context.incrementFunctionInvoke(methodName);
//         }

//         if (owner != nullptr) {
//             String fullName = (owner.toString() + '.' + methodName).toLowerCase();
//             if (provider.getConfig().getPermitFunctions().contains(fullName)) {
//                 return;
//             }

//             checkSchema(visitor, owner);
//         }

//         if (provider.checkDenyFunction(methodName)) {
//             return;
//         }

//         bool isTopNoneFrom = isTopNoneFromSelect(visitor, x);
//         if (isTopNoneFrom) {
//             return;
//         }

//         if (isTopFromDenySchema(visitor, x)) {
//             return;
//         }

//         bool isShow = x->getParent() instanceof MySqlShowGrantsStatement;
//         if (isShow) {
//             return;
//         }

//         if (isWhereOrHaving(x) || checkSqlExpr(x)) {
//             addViolation(visitor, ErrorCode.FUNCTION_DENY, "deny function : " + methodName, x);
//         }

//     }

//     static SQLSelectQueryBlock getQueryBlock(SQLObject_ptr x) {
//         if (x == nullptr) {
//             return nullptr;
//         }

//         if (x instanceof SQLSelectQueryBlock) {
//             return (SQLSelectQueryBlock) x;
//         }

//         SQLObject_ptr parent = x->getParent();

//         if (parent instanceof SQLExpr_ptr) {
//             return getQueryBlock(parent);
//         }

//         if (parent instanceof SQLSelectItem) {
//             return getQueryBlock(parent);
//         }

//         if (parent instanceof SQLSelectQueryBlock) {
//             return (SQLSelectQueryBlock) parent;
//         }

//         return nullptr;
//     }

//     static bool isTopNoneFromSelect(WallVisitor_ptr visitor, SQLObject_ptr x) {
//         for (; ; ) {
//             if ((x->getParent() instanceof SQLExpr_ptr) || (x->getParent() instanceof Item)) {
//                 x = x->getParent();
//             } else {
//                 break;
//             }
//         }

//         if (!(x->getParent() instanceof SQLSelectItem)) {
//             return false;
//         }

//         SQLSelectItem item = (SQLSelectItem) x->getParent();

//         if (!(item.getParent() instanceof SQLSelectQueryBlock)) {
//             return false;
//         }

//         SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) item.getParent();
//         if (!queryBlockFromIsNull(visitor, queryBlock)) {
//             return false;
//         }

//         if (!(queryBlock.getParent() instanceof SQLSelect_ptr)) {
//             return false;
//         }

//         SQLSelect_ptr select = (SQLSelect_ptr) queryBlock.getParent();

//         if (!(select.getParent() instanceof SQLSelectStatement)) {
//             return false;
//         }

//         SQLSelectStatement stmt = (SQLSelectStatement) select.getParent();

//         return stmt.getParent() == nullptr;
//     }

//     static bool isTopFromDenySchema(WallVisitor_ptr visitor, SQLMethodInvokeExpr x) {
//         SQLObject_ptr parent = x->getParent();
//         for (; ; ) {
//             if (parent instanceof SQLExpr_ptr || parent instanceof Item || parent instanceof SQLSelectItem) {
//                 parent = parent.getParent();
//             } else {
//                 break;
//             }
//         }

//         if (parent instanceof SQLSelectQueryBlock) {
//             SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) parent;
//             if (!(queryBlock.getParent() instanceof SQLSelect_ptr)) {
//                 return false;
//             }

//             SQLSelect_ptr select = (SQLSelect_ptr) queryBlock.getParent();

//             if (!(select.getParent() instanceof SQLSelectStatement)) {
//                 return false;
//             }

//             SQLSelectStatement stmt = (SQLSelectStatement) select.getParent();

//             if (stmt.getParent() != nullptr) {
//                 return false;
//             }

//             SQLTableSource from = queryBlock.getFrom();
//             if (from instanceof SQLExprTableSource) {
//                 SQLExpr_ptr fromExpr = ((SQLExprTableSource) from).getExpr();
//                 if (fromExpr instanceof SQLName) {
//                     String fromTableName = fromExpr.toString();
//                     return visitor.isDenyTable(fromTableName);
//                 }
//             }

//             return false;
//         }

//         return false;
//     }

//     static bool checkSchema(WallVisitor_ptr visitor, SQLExpr_ptr x) {
//         WallTopStatementContext topStatementContext = wallTopStatementContextLocal.get();
//         if (topStatementContext != nullptr && (topStatementContext.fromSysSchema || topStatementContext.fromSysTable)) {
//             return true;
//         }

//         if (x instanceof SQLName) {
//             String owner = ((SQLName) x).getSimpleName();
//             owner = WallVisitorUtils.form(owner);
//             if (isInTableSource(x) && !visitor.getProvider().checkDenySchema(owner)) {
//                 if (!isTopStatementWithTableSource(x) && !isFirstSelectTableSource(x) && !isFirstInSubQuery(x)) {
//                     SQLObject_ptr parent = x->getParent();
//                     while (parent != nullptr && !(parent instanceof SQLStatement)) {
//                         parent = parent.getParent();
//                     }

//                     bool sameToTopSelectSchema = false;
//                     if (parent instanceof SQLSelectStatement) {
//                         SQLSelectStatement selectStmt = (SQLSelectStatement) parent;
//                         SQLSelectQuery query = selectStmt.getSelect().getQuery();
//                         if (query instanceof SQLSelectQueryBlock) {
//                             SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query;
//                             SQLTableSource from = queryBlock.getFrom();

//                             while (from instanceof SQLJoinTableSource) {
//                                 from = ((SQLJoinTableSource) from).getLeft();
//                             }
//                             if (from instanceof SQLExprTableSource) {
//                                 SQLExpr_ptr expr = ((SQLExprTableSource) from).getExpr();
//                                 if (expr instanceof SQLPropertyExpr) {
//                                     SQLExpr_ptr schemaExpr = ((SQLPropertyExpr) expr).getOwner();
//                                     if (schemaExpr instanceof SQLIdentifierExpr) {
//                                         String schema = ((SQLIdentifierExpr) schemaExpr).getName();
//                                         schema = form(schema);
//                                         if (schema.equalsIgnoreCase(owner)) {
//                                             sameToTopSelectSchema = true;
//                                         }
//                                     }
//                                 }
//                             }
//                         }
//                     }

//                     if (!sameToTopSelectSchema) {
//                         addViolation(visitor, ErrorCode.SCHEMA_DENY, "deny schema : " + owner, x);
//                     }
//                 } else {
//                     if (topStatementContext != nullptr) {
//                         topStatementContext.setFromSysSchema(bool.TRUE);
//                         clearViolation(visitor);
//                     }
//                 }
//                 return true;
//             }

//             if (visitor.getConfig().isDenyObjects(owner)) {
//                 addViolation(visitor, ErrorCode.OBJECT_DENY, "deny object : " + owner, x);
//                 return true;
//             }
//         }

//         // if (ownerExpr instanceof SQLPropertyExpr) {
//         if (x instanceof SQLPropertyExpr) {
//             return checkSchema(visitor, ((SQLPropertyExpr) x).getOwner());
//         }

//         return true;
//     }

//     static bool isInTableSource(SQLObject_ptr x) {
//         for (; ; ) {
//             if (x instanceof SQLExpr_ptr) {
//                 x = x->getParent();
//             } else {
//                 break;
//             }
//         }

//         if (x instanceof SQLExprTableSource) {
//             return true;
//         }
//         return false;
//     }

//     static bool isFirstInSubQuery(SQLObject_ptr x) {
//         for (; ; ) {
//             if (x instanceof SQLExpr_ptr) {
//                 x = x->getParent();
//             } else {
//                 break;
//             }
//         }

//         if (!(x instanceof SQLExprTableSource)) {
//             return false;
//         }

//         SQLSelect_ptr sqlSelect = nullptr;
//         SQLObject_ptr parent = x->getParent();
//         while (parent != nullptr) {
//             if (parent instanceof SQLSelect_ptr) {
//                 sqlSelect = (SQLSelect_ptr) parent;
//                 break;
//             }

//             x = parent;
//             parent = x->getParent();
//         }

//         if (sqlSelect == nullptr) {
//             return false;
//         }

//         parent = sqlSelect.getParent();
//         if (!(parent instanceof SQLInSubQueryExpr && isFirst(parent))) {
//             return false;
//         }

//         SQLInSubQueryExpr sqlInSubQueryExpr = (SQLInSubQueryExpr) parent;
//         if (!(sqlInSubQueryExpr.getParent() instanceof SQLSelectQueryBlock)) {
//             return false;
//         }

//         SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) sqlInSubQueryExpr.getParent();
//         if (!(queryBlock.getParent() instanceof SQLSelect_ptr)) {
//             return false;
//         }

//         SQLSelect_ptr select = (SQLSelect_ptr) queryBlock.getParent();
//         if (!(select.getParent() instanceof SQLSelectStatement)) {
//             return false;
//         }

//         SQLSelectStatement stmt = (SQLSelectStatement) select.getParent();
//         return stmt.getParent() == nullptr;
//     }

//     static bool isFirstSelectTableSource(SQLObject_ptr x) {
//         for (; ; ) {
//             if (x instanceof SQLExpr_ptr) {
//                 x = x->getParent();
//             } else {
//                 break;
//             }
//         }

//         if (!(x instanceof SQLExprTableSource)) {
//             return false;
//         }

//         SQLSelectQueryBlock queryBlock = nullptr;
//         SQLObject_ptr parent = x->getParent();
//         while (parent != nullptr) {
//             // if (parent instanceof SQLJoinTableSource) {
//             // SQLJoinTableSource join = (SQLJoinTableSource) parent;
//             // if (join.getRight() == x && hasTableSource(join.getLeft())) {
//             // return false;
//             // }
//             // }

//             if (parent instanceof SQLSelectQueryBlock) {
//                 queryBlock = (SQLSelectQueryBlock) parent;
//                 break;
//             }

//             x = parent;
//             parent = x->getParent();
//         }

//         if (queryBlock == nullptr) {
//             return false;
//         }

//         bool isWhereQueryExpr = false;
//         bool isSelectItem = false;
//         do {
//             x = parent;
//             parent = parent.getParent();
//             if (parent instanceof SQLUnionQuery) {
//                 SQLUnionQuery union = (SQLUnionQuery) parent;
//                 if (union.getRight() == x && hasTableSource(union.getLeft())) {
//                     return false;
//                 }
//             } else if (parent instanceof SQLQueryExpr || parent instanceof SQLInSubQueryExpr
//                     || parent instanceof SQLExistsExpr) {
//                 isWhereQueryExpr = isWhereOrHaving(parent);
//             } else if (parent instanceof SQLSelectItem) {
//                 isSelectItem = true;
//             } else if ((isWhereQueryExpr || isSelectItem) && parent instanceof SQLSelectQueryBlock) {
//                 if (hasTableSource((SQLSelectQueryBlock) parent)) {
//                     return false;
//                 }
//             }

//         } while (parent != nullptr);

//         return true;
//     }

//     static bool hasTableSource(SQLSelectQuery x) {
//         if (x instanceof SQLUnionQuery) {
//             SQLUnionQuery union = (SQLUnionQuery) x;
//             return hasTableSource(union.getLeft()) || hasTableSource(union.getRight());
//         } else if (x instanceof SQLSelectQueryBlock) {
//             return hasTableSource(((SQLSelectQueryBlock) x).getFrom());
//         }

//         return false;
//     }

//     static bool hasTableSource(SQLTableSource x) {
//         if (x == nullptr) {
//             return false;
//         }

//         if (x instanceof SQLExprTableSource) {
//             SQLExpr_ptr fromExpr = ((SQLExprTableSource) x).getExpr();
//             if (fromExpr instanceof SQLName) {
//                 String name = fromExpr.toString();
//                 name = form(name);
//                 if (name.equalsIgnoreCase("DUAL")) {
//                     return false;
//                 }
//             }
//             return true;
//         } else if (x instanceof SQLJoinTableSource) {
//             SQLJoinTableSource join = (SQLJoinTableSource) x;
//             return hasTableSource(join.getLeft()) || hasTableSource(join.getRight());
//         } else if (x instanceof SQLSubqueryTableSource) {
//             return hasTableSource(((SQLSubqueryTableSource) x).getSelect().getQuery());
//         }

//         return false;
//     }

//     static bool isTopStatementWithTableSource(SQLObject_ptr x) {
//         for (; ; ) {
//             if (x instanceof SQLExpr_ptr) {
//                 x = x->getParent();
//             } else {
//                 break;
//             }
//         }

//         if (x instanceof SQLExprTableSource) {
//             x = x->getParent();

//             if (x instanceof SQLStatement) {
//                 x = x->getParent();
//                 if (x == nullptr) {
//                     return true;
//                 }
//             }
//         }
//         return false;
//     }

//     static bool isTopSelectItem(SQLObject_ptr x) {
//         for (; ; ) {
//             if ((x->getParent() instanceof SQLExpr_ptr) || (x->getParent() instanceof Item)) {
//                 x = x->getParent();
//             } else {
//                 break;
//             }
//         }

//         if (!(x->getParent() instanceof SQLSelectItem)) {
//             return false;
//         }

//         SQLSelectItem item = (SQLSelectItem) x->getParent();
//         return isTopSelectStatement(item.getParent());
//     }

//     static bool isTopSelectStatement(SQLObject_ptr x) {
//         if (!(x instanceof SQLSelectQueryBlock)) {
//             return false;
//         }

//         SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) x;
//         if (!(queryBlock.getParent() instanceof SQLSelect_ptr)) {
//             return false;
//         }

//         SQLSelect_ptr select = (SQLSelect_ptr) queryBlock.getParent();
//         if (!(select.getParent() instanceof SQLSelectStatement)) {
//             return false;
//         }

//         SQLSelectStatement stmt = (SQLSelectStatement) select.getParent();
//         return stmt.getParent() == nullptr;
//     }

//     static bool isTopSelectOutFile(MySqlOutFileExpr x) {
//         if (!(x->getParent() instanceof SQLExprTableSource)) {
//             return false;
//         }
//         SQLExprTableSource tableSource = (SQLExprTableSource) x->getParent();
//         return isTopSelectStatement(tableSource.getParent());
//     }

//     static bool check(WallVisitor_ptr visitor, SQLExprTableSource x) {
//         WallTopStatementContext topStatementContext = wallTopStatementContextLocal.get();

//         SQLExpr_ptr expr = x->getExpr();
//         if (expr instanceof SQLPropertyExpr) {
//             bool checkResult = checkSchema(visitor, ((SQLPropertyExpr) expr).getOwner());
//             if (!checkResult) {
//                 return false;
//             }
//         }

//         if (expr instanceof SQLName) {
//             String tableName = ((SQLName) expr).getSimpleName();

//             WallContext context = WallContext.current();
//             if (context != nullptr) {
//                 WallSqlTableStat tableStat = context.getTableStat(tableName);
//                 if (tableStat != nullptr) {
//                     SQLObject_ptr parent = x->getParent();

//                     while (parent instanceof SQLTableSource) {
//                         parent = parent.getParent();
//                     }

//                     if (parent instanceof SQLSelectQueryBlock) {
//                         SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) parent;
//                         if (x == queryBlock.getInto()) {
//                             tableStat.incrementSelectIntoCount();
//                         } else {
//                             tableStat.incrementSelectCount();
//                         }
//                     } else if (parent instanceof SQLTruncateStatement) {
//                         tableStat.incrementTruncateCount();
//                     } else if (parent instanceof SQLInsertStatement) {
//                         tableStat.incrementInsertCount();
//                     } else if (parent instanceof SQLDeleteStatement) {
//                         tableStat.incrementDeleteCount();
//                     } else if (parent instanceof SQLUpdateStatement) {
//                         tableStat.incrementUpdateCount();
//                     } else if (parent instanceof SQLReplaceStatement) {
//                         tableStat.incrementReplaceCount();
//                     }
//                 }
//             }

//             if (topStatementContext != nullptr && (topStatementContext.fromSysSchema || topStatementContext.fromSysTable)) {
//                 return true;
//             }

//             if (visitor.isDenyTable(tableName)
//                     && !(topStatementContext != nullptr && topStatementContext.fromPermitTable())) {
//                 if (isTopStatementWithTableSource(x) || isFirstSelectTableSource(x)) {
//                     if (topStatementContext != nullptr) {
//                         topStatementContext.setFromSysTable(bool.TRUE);
//                         clearViolation(visitor);
//                     }
//                     return false;
//                 }

//                 bool isTopNoneFrom = isTopNoneFromSelect(visitor, x);
//                 if (isTopNoneFrom) {
//                     return false;
//                 }

//                 addViolation(visitor, ErrorCode.TABLE_DENY, "deny table : " + tableName, x);
//                 return false;
//             }

//             if (visitor.getConfig().getPermitTables().contains(tableName)) {
//                 if (isFirstSelectTableSource(x)) {
//                     if (topStatementContext != nullptr) {
//                         topStatementContext.setFromPermitTable(bool.TRUE);
//                     }
//                     return false;
//                 }
//             }
//         }

//         return true;
//     }

void WallVisitorUtils::addViolation(WallVisitor_ptr visitor, int errorCode, std::string message, SQLObject_ptr x) {
        visitor->addViolation(IllegalSQLObjectViolation_ptr(new IllegalSQLObjectViolation(errorCode, message, visitor->toSQL(x))));
    }

//     static void clearViolation(WallVisitor_ptr visitor) {
//         visitor.getViolations().clear();
//     }

//     static bool checkUnion(WallVisitor_ptr visitor, SQLUnionQuery x) {
//         if (x->getRelations().size() > 2) {
//             for (int i = 0; i < x->getRelations().size(); i++) {
//                 SQLSelectQuery item = x->getRelations().get(i);
//                 if (item instanceof SQLSelectQueryBlock && queryBlockFromIsNull(visitor, item)) {
//                     continue;
//                 }

//                 item.accept(visitor);
//             }
//             return false;
//         }

//         {
//             SQLUnionOperator operator = x->getOperator();
//             SQLSelectQuery left = x->getLeft();
//             SQLSelectQuery right = x->getRight();

//             bool bracket = x->isParenthesized() && !(x->getParent() instanceof SQLUnionQueryTableSource);

//             if ((!bracket)
//                     && left instanceof SQLUnionQuery
//                     && ((SQLUnionQuery) left).getOperator() == operator
//                     && !right.isParenthesized()
//                     && x->getOrderBy() == nullptr) {
//                 SQLUnionQuery leftUnion = (SQLUnionQuery) left;

//                 List<SQLSelectQuery> rights = new ArrayList<SQLSelectQuery>();
//                 rights.add(right);

//                 for (; ; ) {
//                     SQLSelectQuery leftLeft = leftUnion.getLeft();
//                     SQLSelectQuery leftRight = leftUnion.getRight();

//                     if ((!leftUnion.isParenthesized())
//                             && leftUnion.getOrderBy() == nullptr
//                             && (!leftLeft.isParenthesized())
//                             && (!leftRight.isParenthesized())
//                             && leftLeft instanceof SQLUnionQuery
//                             && ((SQLUnionQuery) leftLeft).getOperator() == operator) {
//                         rights.add(leftRight);
//                         leftUnion = (SQLUnionQuery) leftLeft;
//                         continue;
//                     } else {
//                         rights.add(leftRight);
//                         rights.add(leftLeft);
//                     }
//                     break;
//                 }

//                 for (int i = rights.size() - 1; i >= 0; i--) {
//                     SQLSelectQuery item = rights.get(i);

//                     if (item instanceof SQLSelectQueryBlock && queryBlockFromIsNull(visitor, item)) {
//                         continue;
//                     }

//                     item.accept(visitor);
//                 }
//                 return false;
//             }
//         }

//         if (x->getOperator() == SQLUnionOperator.MINUS && !visitor.getConfig().isMinusAllow()) {
//             addViolation(visitor, ErrorCode.INTERSET_NOT_ALLOW, "minus not allow", x);
//             return true;
//         }

//         if (x->getOperator() == SQLUnionOperator.INTERSECT && !visitor.getConfig().isIntersectAllow()) {
//             addViolation(visitor, ErrorCode.INTERSET_NOT_ALLOW, "intersect not allow", x);
//             return true;
//         }

//         if (!WallVisitorUtils.queryBlockFromIsNull(visitor, x->getLeft())
//                 && WallVisitorUtils.queryBlockFromIsNull(visitor, x->getRight())) {
//             bool isTopUpdateStatement = false;
//             bool isTopInsertStatement = false;
//             SQLObject_ptr selectParent = x->getParent();
//             while (selectParent instanceof SQLSelectQuery //
//                     || selectParent instanceof SQLJoinTableSource //
//                     || selectParent instanceof SQLSubqueryTableSource //
//                     || selectParent instanceof SQLSelect_ptr) {
//                 selectParent = selectParent.getParent();
//             }

//             if (selectParent instanceof SQLUpdateStatement) {
//                 isTopUpdateStatement = true;
//             }

//             if (selectParent instanceof SQLInsertStatement) {
//                 isTopInsertStatement = true;
//             }

//             if (isTopUpdateStatement || isTopInsertStatement) {
//                 return true;
//             }

//             if (x->getLeft() instanceof SQLSelectQueryBlock) {
//                 SQLSelectQueryBlock left = (SQLSelectQueryBlock) x->getLeft();
//                 SQLTableSource tableSource = left.getFrom();
//                 if (left.getWhere() == nullptr && tableSource != nullptr && tableSource instanceof SQLExprTableSource) {
//                     return true;
//                 }
//             }

//             WallContext context = WallContext.current();
//             if (context != nullptr) {
//                 context.incrementUnionWarnings();
//             }

//             if (((x->getOperator() == SQLUnionOperator.UNION || x->getOperator() == SQLUnionOperator.UNION_ALL || x->getOperator() == SQLUnionOperator.DISTINCT)
//                     && visitor.getConfig().isSelectUnionCheck() && visitor.isSqlEndOfComment())
//                     || (x->getOperator() == SQLUnionOperator.MINUS && visitor.getConfig().isSelectMinusCheck())
//                     || (x->getOperator() == SQLUnionOperator.INTERSECT && visitor.getConfig().isSelectIntersectCheck())
//                     || (x->getOperator() == SQLUnionOperator.EXCEPT && visitor.getConfig().isSelectExceptCheck())) {
//                 addViolation(visitor, ErrorCode.UNION,
//                         x->getOperator().toString() + " query not contains 'from clause'", x);
//             }
//         }

//         return true;
//     }

//     static bool queryBlockFromIsNull(WallVisitor_ptr visitor, SQLSelectQuery query) {
//         return queryBlockFromIsNull(visitor, query, true);
//     }

//     static bool queryBlockFromIsNull(WallVisitor_ptr visitor, SQLSelectQuery query, bool checkSelectConst) {
//         if (query instanceof SQLSelectQueryBlock) {
//             SQLSelectQueryBlock queryBlock = (SQLSelectQueryBlock) query;
//             SQLTableSource from = queryBlock.getFrom();

//             if (queryBlock.getSelectList().size() < 1) {
//                 return false;
//             }

//             if (from == nullptr) {
//                 bool itemIsConst = true;
//                 bool itemHasAlias = false;
//                 for (SQLSelectItem item : queryBlock.getSelectList()) {
//                     if (item.getExpr() instanceof SQLIdentifierExpr || item.getExpr() instanceof SQLPropertyExpr) {
//                         itemIsConst = false;
//                         break;
//                     }
//                     if (item.getAlias() != nullptr) {
//                         itemHasAlias = true;
//                         break;
//                     }
//                 }
//                 if (itemIsConst && !itemHasAlias) {
//                     return true;
//                 } else {
//                     return false;
//                 }
//             }

//             if (from instanceof SQLExprTableSource) {
//                 SQLExpr_ptr fromExpr = ((SQLExprTableSource) from).getExpr();
//                 if (fromExpr instanceof SQLName) {
//                     String name = fromExpr.toString();

//                     name = form(name);

//                     if (name.equalsIgnoreCase("DUAL")) {
//                         return true;
//                     }
//                 }
//             }

//             if (queryBlock.getSelectList().size() == 1
//                     && queryBlock.getSelectList().get(0).getExpr() instanceof SQLAllColumnExpr) {
//                 if (from instanceof SQLSubqueryTableSource) {
//                     SQLSelectQuery subQuery = ((SQLSubqueryTableSource) from).getSelect().getQuery();
//                     if (queryBlockFromIsNull(visitor, subQuery)) {
//                         return true;
//                     }
//                 }
//             }

//             if (checkSelectConst) {
//                 SQLExpr_ptr where = queryBlock.getWhere();
//                 if (where != nullptr) {
//                     Object_ptr whereValue = getValue(visitor, where);
//                     if (bool.TRUE == whereValue) {
//                         bool allIsConst = true;
//                         for (SQLSelectItem item : queryBlock.getSelectList()) {
//                             if (getValue(visitor, item.getExpr()) == nullptr) {
//                                 allIsConst = false;
//                                 break;
//                             }
//                         }
//                         if (allIsConst) {
//                             return true;
//                         }
//                     }
//                 }
//             }
//         }

//         return false;
//     }

//     static String form(String name) {
//         if (name.startsWith("\"") && name.endsWith("\"")) {
//             name = name.substring(1, name.length() - 1);
//         }

//         if (name.startsWith("'") && name.endsWith("'")) {
//             name = name.substring(1, name.length() - 1);
//         }

//         if (name.startsWith("`") && name.endsWith("`")) {
//             name = name.substring(1, name.length() - 1);
//         }

//         name = name.toLowerCase();
//         return name;
//     }

//     static void loadResource(Set<String> names, String resource) {
//         try {
//             bool hasResource = false;
//             ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
//             if (classLoader != nullptr) {
//                 Enumeration<URL> e = Thread.currentThread().getContextClassLoader().getResources(resource);
//                 while (e.hasMoreElements()) {
//                     URL url = e.nextElement();
//                     InputStream in = nullptr;
//                     try {
//                         in = url.openStream();
//                         readFromInputStream(names, in);

//                         hasResource = true;
//                     } finally {
//                         JdbcUtils.close(in);
//                     }
//                 }
//             }

//             // for aliyun odps
//             if (!hasResource) {
//                 if (!resource.startsWith("/")) {
//                     resource = "/" + resource;
//                 }

//                 InputStream in = nullptr;
//                 try {
//                     in = WallVisitorUtils.class.getResourceAsStream(resource);
//                     if (in != nullptr) {
//                         readFromInputStream(names, in);
//                     }
//                 } finally {
//                     JdbcUtils.close(in);
//                 }
//             }
//         } catch (IOException e) {
//             LOG.error("load oracle deny tables errror", e);
//         }
//     }

//     static void readFromInputStream(Set<String> names, InputStream in) throws IOException {
//         BufferedReader reader = nullptr;
//         try {
//             reader = new BufferedReader(new InputStreamReader(in));
//             for (; ; ) {
//                 String line = reader.readLine();
//                 if (line == nullptr) {
//                     break;
//                 }
//                 line = line.trim();
//                 if (line.length() > 0) {
//                     line = line.toLowerCase();
//                     names.add(line);
//                 }
//             }
//         } finally {
//             JdbcUtils.close(reader);
//         }
//     }

//     static void preVisitCheck(WallVisitor_ptr visitor, SQLObject_ptr x) {
//         WallConfig config = visitor.getProvider().getConfig();

//         if (!(x instanceof SQLStatement)) {
//             return;
//         }

//         bool allow = false;
//         int errorCode;
//         String denyMessage;
//         if (x instanceof SQLCommentStatement) {
//             return;
//         } else if (x instanceof SQLInsertStatement) {
//             allow = config.isInsertAllow();
//             denyMessage = "insert not allow";
//             errorCode = ErrorCode.INSERT_NOT_ALLOW;
//         } else if (x instanceof SQLSelectStatement) {
//             allow = true;
//             denyMessage = "select not allow";
//             errorCode = ErrorCode.SELECT_NOT_ALLOW;
//         } else if (x instanceof SQLDeleteStatement) {
//             allow = config.isDeleteAllow();
//             denyMessage = "delete not allow";
//             errorCode = ErrorCode.DELETE_NOT_ALLOW;
//         } else if (x instanceof SQLUpdateStatement) {
//             allow = config.isUpdateAllow();
//             denyMessage = "update not allow";
//             errorCode = ErrorCode.UPDATE_NOT_ALLOW;
//         } else if (x instanceof OracleMultiInsertStatement
//                 || x instanceof OracleMultiInsertStatement.InsertIntoClause) {
//             allow = true;
//             denyMessage = "multi-insert not allow";
//             errorCode = ErrorCode.INSERT_NOT_ALLOW;
//         } else if (x instanceof SQLMergeStatement) {
//             allow = config.isMergeAllow();
//             denyMessage = "merge not allow";
//             errorCode = ErrorCode.MERGE_NOT_ALLOW;
//         } else if (x instanceof SQLCallStatement
//                 || x instanceof SQLServerExecStatement
//                 || x instanceof OracleExecuteImmediateStatement) {
//             allow = config.isCallAllow();
//             denyMessage = "call not allow";
//             errorCode = ErrorCode.CALL_NOT_ALLOW;
//         } else if (x instanceof SQLTruncateStatement) {
//             allow = config.isTruncateAllow();
//             denyMessage = "truncate not allow";
//             errorCode = ErrorCode.TRUNCATE_NOT_ALLOW;
//         } else if (x instanceof SQLCreateStatement) {
//             allow = config.isCreateTableAllow();
//             denyMessage = "create table not allow";
//             errorCode = ErrorCode.CREATE_TABLE_NOT_ALLOW;
//         } else if (x instanceof MySqlRenameTableStatement) {
//             allow = config.isRenameTableAllow();
//             denyMessage = "rename table not allow";
//             errorCode = ErrorCode.RENAME_TABLE_NOT_ALLOW;
//         } else if (x instanceof SQLAlterStatement) {
//             allow = config.isAlterTableAllow();
//             denyMessage = "alter table not allow";
//             errorCode = ErrorCode.ALTER_TABLE_NOT_ALLOW;
//         } else if (x instanceof SQLDropStatement) {
//             allow = config.isDropTableAllow();
//             denyMessage = "drop table not allow";
//             errorCode = ErrorCode.DROP_TABLE_NOT_ALLOW;
//         } else if (x instanceof SQLSetStatement) {
//             allow = config.isSetAllow();
//             denyMessage = "set not allow";
//             errorCode = ErrorCode.SET_NOT_ALLOW;
//         } else if (x instanceof SQLReplaceStatement) {
//             allow = config.isReplaceAllow();
//             denyMessage = "replace not allow";
//             errorCode = ErrorCode.REPLACE_NOT_ALLOW;
//         } else if (x instanceof SQLDescribeStatement
//                 || (x instanceof MySqlExplainStatement && ((MySqlExplainStatement) x).isDescribe())) {
//             allow = config.isDescribeAllow();
//             denyMessage = "describe not allow";
//             errorCode = ErrorCode.DESC_NOT_ALLOW;
//         } else if (x instanceof SQLShowStatement) {
//             allow = config.isShowAllow();
//             denyMessage = "show not allow";
//             errorCode = ErrorCode.SHOW_NOT_ALLOW;
//         } else if (x instanceof SQLCommitStatement) {
//             allow = config.isCommitAllow();
//             denyMessage = "commit not allow";
//             errorCode = ErrorCode.COMMIT_NOT_ALLOW;
//         } else if (x instanceof SQLRollbackStatement) {
//             allow = config.isRollbackAllow();
//             denyMessage = "rollback not allow";
//             errorCode = ErrorCode.ROLLBACK_NOT_ALLOW;
//         } else if (x instanceof SQLUseStatement) {
//             allow = config.isUseAllow();
//             denyMessage = "use not allow";
//             errorCode = ErrorCode.USE_NOT_ALLOW;
//         } else if (x instanceof MySqlHintStatement) {
//             allow = config.isHintAllow();
//             denyMessage = "hint not allow";
//             errorCode = ErrorCode.HINT_NOT_ALLOW;
//         } else if (x instanceof SQLLockTableStatement) {
//             allow = config.isLockTableAllow();
//             denyMessage = "lock table not allow";
//             errorCode = ErrorCode.LOCK_TABLE_NOT_ALLOW;
//         } else if (x instanceof OracleLockTableStatement) {
//             allow = config.isLockTableAllow();
//             denyMessage = "lock table not allow";
//             errorCode = ErrorCode.LOCK_TABLE_NOT_ALLOW;
//         } else if (x instanceof SQLStartTransactionStatement) {
//             allow = config.isStartTransactionAllow();
//             denyMessage = "start transaction not allow";
//             errorCode = ErrorCode.START_TRANSACTION_NOT_ALLOW;
//         } else if (x instanceof SQLBlockStatement) {
//             allow = config.isBlockAllow();
//             denyMessage = "block statement not allow";
//             errorCode = ErrorCode.BLOCK_NOT_ALLOW;
//         } else if (x instanceof SQLExplainStatement
//                 || x instanceof MySqlOptimizeStatement
//                 || x instanceof SQLRefreshMaterializedViewStatement
//         ) {
//             allow = true;
//             errorCode = 0;
//             denyMessage = nullptr;
//         } else {
//             allow = config.isNoneBaseStatementAllow();
//             errorCode = ErrorCode.NONE_BASE_STATEMENT_NOT_ALLOW;
//             denyMessage = x->getClass() + " not allow";
//         }

//         if (!allow) {
//             addViolation(visitor, errorCode, denyMessage, x);
//         }
//     }

//     static void check(WallVisitor_ptr visitor, SQLCommentHint x) {
//         if (!visitor.getConfig().isHintAllow()) {
//             addViolation(visitor, ErrorCode.EVIL_HINTS, "hint not allow", x);
//             return;
//         }

//         String text = x->getText();
//         text = text.trim();
//         if (text.startsWith("!")) {
//             text = text.substring(1);
//         }

//         if (text.length() == 0) {
//             return;
//         }

//         int pos = 0;
//         for (; pos < text.length(); pos++) {
//             char ch = text.charAt(pos);
//             if (ch >= '0' && ch <= '9') {
//                 continue;
//             } else {
//                 break;
//             }
//         }

//         if (pos == 5) {
//             text = text.substring(5);
//             text = text.trim();
//         }

//         text = text.toUpperCase();

//         bool isWhite = false;
//         for (String hint : whiteHints) {
//             if (text.equals(hint)) {
//                 isWhite = true;
//                 break;
//             }
//         }

//         if (!isWhite) {
//             if (text.startsWith("FORCE INDEX") || text.startsWith("IGNORE INDEX")) {
//                 isWhite = true;
//             }
//         }

//         if (!isWhite) {
//             if (text.startsWith("SET")) {
//                 SQLStatementParser parser = new MySqlStatementParser(text);
//                 List<SQLStatement> statementList = parser.parseStatementList();
//                 if (statementList != nullptr && statementList.size() > 0) {
//                     SQLStatement statement = statementList.get(0);
//                     if (statement instanceof SQLSetStatement) {
//                         isWhite = true;
//                     }
//                 }
//             }
//         }

//         if ((!isWhite) && visitor.getDbType() == DbType.oracle) {
//             if (text.startsWith("+")) {
//                 isWhite = true;
//             }
//         }

//         if (!isWhite) {
//             addViolation(visitor, ErrorCode.EVIL_HINTS, "hint not allow", x);
//         }
//     }

//     static void check(WallVisitor_ptr visitor, SQLJoinTableSource x) {
//         SQLExpr_ptr condition = x->getCondition();
//         if (condition instanceof SQLName) {
//             addViolation(visitor, ErrorCode.INVALID_JOIN_CONDITION, "invalid join condition", x);
//         }
//     }
// }
